Deep dive into the Java virtual machine and memory management

1. The execution process of the java program

     java source file -> parser -> class file -> java class loader -> java runtime data area -> execution engine

  

2. Let's take a look at the java runtime data area next

     It includes program counter, virtual machine stack, local method stack, method area, and heap. Among them, program counter, virtual machine stack, local method area belong to instructions, and method area and heap belong to data.

 1. Program counter

      It is used to indicate which instruction the program executes, which is logically the same as the function of the program counter in assembly language. The JVM specification stipulates that if the thread executes a non-native method, the program counter points to the address and line number of the bytecode instruction being executed by the current thread. If the thread executes the native method, the value in the program counter is undefined. Each thread has its own independent program counter. why? Because under multi-threading, a CPU core can only execute instructions in one thread at a time, so in order to enable each thread to resume the execution of the program before the switch after thread switching, each thread has its own independent program. counter.

2. Java Virtual Machine Stack ( VM Stack )

     The Java virtual machine stack stores stack frames one by one. The stack is a data structure, and the data structure is used to store data, so the virtual machine stack is also used to store data. Stores the data, instructions and return addresses required by the current thread running method. When a program executes a method, it creates a stack frame and pushes it onto the stack. After execution, the stack is removed from the stack frame. The virtual machine stack has: local variable table, operand stack, dynamic link, method exit.

       Local variable table:

             The table that stores local variables, the basic data types of java ( boolean, byte, char, short, int, float, long, double ), the reference of the object (reference type, it is not equivalent to the object itself, it may be a pointer to the object The reference pointer of the starting address, or it may point to a handle representing the object or other location related to this object) and returnAddress type (pointing to the address of a bytecode instruction), where 64-bit long and double type data It will occupy 2 local variable spaces (Slot), and the rest of the data types only occupy 1. The size of the local variable table is determined by the compiler, so the size of the local variable table does not change during program execution. In the Java virtual machine specification, two exception conditions are specified for this area: if the stack depth requested by the thread is greater than the depth allowed by the virtual machine, a StackOverflowError exception will be thrown; if the virtual machine stack can be dynamically expanded (most current Java Virtual machines can be dynamically expanded, but the Java virtual machine specification also allows a fixed-length virtual machine stack). If enough memory cannot be applied for during expansion, an OutOfMemoryError exception will be thrown.

        Operand stack:

           The virtual machine uses the operand stack as its work area. All calculations in the program are done with the help of the operand stack. Most instructions pop data from here, perform the operation, and then push the result back to the operand. stack.

       Dynamic connection:
         Each stack frame contains a reference to the method to which the stack frame belongs in the runtime constant pool (pointing to the runtime constant pool: constants in the class may need to be used during method execution, and this reference is held to support Dynamic linking during method invocation.
      Method return address:
    When a method finishes executing, it needs to return to the place where it was called before, so a method return address must be saved in the stack frame.
      Native Method Stack :
      本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则 为虚拟机使用到的Native方法服务。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。
三、方法区(Method Area):
          方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、以及编译器编译后的代码等。运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。在JVM规范中,没有强制要求方法区必须实现垃圾回收。很多人习惯将方法区称为“永久代”,是因为HotSpot虚拟机以永久代来实现方法区,从而JVM的垃圾收集器可以像管理堆区一样管理这部分区域,从而不需要专门为这部分设计垃圾回收机制。不过自从JDK7之后,Hotspot虚拟机便将运行时常量池从永久代移除了。
 四 、堆(Heap):
      在C语言中,程序员可以通过malloc函数和free函数在堆上申请和释放空间。那么在Java中是怎么样的呢?Java中的堆是用来存储对象本身的以及数组(当然,数组引用是存放在Java栈中的),几乎所有的对象实例都在这里分配内存。在Java中,程序员基本不用去关心空间释放的问题,Java的垃圾回收机制会自动进行处理。另外,堆是被所有线程共享的,在JVM中只有一个堆。
、内存管理:

             JVM将内存划分为6个部分:PC寄存器(也叫程序计数器)、虚拟机栈、堆、方法区、运行时常量池、本地方法栈

          

   

  • PC寄存器(程序计数器):用于记录当前线程运行时的位置,每一个线程都有一个独立的程序计数器,线程的阻塞、恢复、挂起等一系列操作都需要程序计数器的参与,因此必须是线程私有的。

  • java 虚拟机栈:在创建线程时创建的,用来存储栈帧,因此也是线程私有的。java程序中的方法在执行时,会创建一个栈帧,用于存储方法运行时的临时数据和中间结果,包括局部变量表、操作数栈、动态链接、方法出口等信息。这些栈帧就存储在栈中。如果栈深度大于虚拟机允许的最大深度,则抛出StackOverflowError异常。

    • 局部变量表:方法的局部变量列表,在编译时就写入了class文件
    • 操作数栈:int x = 1; 就需要将 1 压入操作数栈,再将 1 赋值给变量x
  • java堆:java堆被所有线程共享,堆的主要作用就是存储对象。如果堆空间不够,但扩展时又不能申请到足够的内存时,则抛出OutOfMemoryError异常。

  •     
    • 方法区:方发区被各个线程共享,用于存储静态变量、运行时常量池等信息。

    • 本地方法栈:本地方法栈的主要作用就是支持native方法,比如在java中调用C/C++

     、垃圾回收机制:

 

      

    (2)、可达性分析

    设立若干根对象(GC Root),每个对象都是一个子节点,当一个对象找不到根时,就认为该对象不可达。

   

    3、怎么回收?

  •         标记——清除算法
  •        复制算法
  •        分代算法

      (1)、标记——清除算法

      遍历所有的GC Root,分别标记处可达的对象和不可达的对象,然后将不可达的对象回收。

      缺点是:效率低、回收得到的空间不连续

      (2)、复制算法

     将内存分为两块,每次只使用一块。当这一块内存满了,就将还存活的对象复制到另一块上,并且严格按照内存地址排列,然后把已使用的那块内存统一回   收。

       优点是:能够得到连续的内存空间 
       缺点是:浪费了一半内存

   

      (3)、分代算法

     在java中,把内存中的对象按生命长短分为:

  •      新生代:活不了多久就go die 了,比如局部变量
  •      老年代:老不死的,活的久但也会go die,比如一些生命周期长的对象
  •      永久代:千年王八万年龟,不死,比如加载的class信息
  •      有一点需要注意:新生代和老年代存储在java虚拟机堆上 ;永久代存储在方法区上

  

     补充:java finalize()方法:

    在被GC回收前,可以做一些操作,比如释放资源。有点像析构函数,但是一个对象只能调用一次finalize()方法。

   

    

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325025569&siteId=291194637