JVM memory area division

Friends who have learned the C language know that the C compiler often divides the managed area into data segments and code segments when dividing the memory area. The data segment includes heap, stack and static data area. So in the Java language, how is the memory divided?

  Since Java programs are executed by the JVM, when we talk about the division of Java memory areas, we actually refer to the division of JVM memory areas. Before discussing the division of JVM memory areas, let's take a look at the specific execution process of Java programs:

                                       

  As shown in the figure above, first, the Java source code file (.java suffix) will be compiled into a bytecode file (.class suffix) by the Java compiler, and then the class loader in the JVM loads the bytecode file of each class, loading After completion, it is handed over to the JVM execution engine for execution. During the entire program execution process, the JVM will use a space to store the data and related information needed during program execution. This space is generally referred to as the Runtime Data Area, which is what we often call the JVM. RAM. Therefore, the memory management we often talk about in Java is to manage this space (how to allocate and reclaim memory space).

  After knowing what JVM memory is, let's discuss how this space is divided into areas. Is there a stack and heap like in the C language?

1. What parts does the runtime data area include?

  According to the "Java Virtual Machine Specification", the runtime data area usually includes these parts: Program Counter Register, Java Stack (VM Stack), Native Method Stack (Native Method Stack), Method Area (Method Area) ), heap (Heap).

  As shown in the figure above, the runtime data area in the JVM should include these parts. Although it is stipulated in the JVM specification that the data area should include these parts when the program is running during execution, there is no regulation on how to implement it, and different virtual machine manufacturers can have different implementation methods.

2. What data is stored in each part of the runtime data area?

  Let's take a look at what data each part of the runtime data area is used to store during program execution.

1. Program Counter

  Program Counter (Program Counter Register), also known as PC register. Friends who must have learned assembly language are not unfamiliar with the concept of program counter. In assembly language, program counter refers to the register in the CPU, which stores the address of the instruction currently executed by the program (it can also be said to save the address of the next instruction. address of the storage unit), when the CPU needs to execute an instruction, it needs to obtain the address of the storage unit where the instruction currently needs to be executed is located from the program counter, and then obtain the instruction according to the obtained address. After the instruction is obtained, the program counter will automatically increase 1 or obtain the address of the next instruction according to the transfer pointer, and so on, until all instructions are executed.

  Although the program counter in the JVM is not a physical and conceptual CPU register like the program counter in assembly language, the function of the program counter in the JVM is logically equivalent to the function of the program counter in assembly language, that is Say is used to indicate which instruction to execute.

  Since in the JVM, multithreading obtains the CPU execution time by switching threads in turn, therefore, at any specific moment, the core of a CPU will only execute the instructions in one thread. After the switch, the program execution position before the switch can be restored. Each thread needs to have its own independent program counter and cannot interfere with each other, otherwise the normal execution order of the program will be affected. So, so to speak, the program counter is private to each thread.

  It is stipulated in the JVM specification that if the thread executes a non-native method, the program counter stores the address of the instruction that needs to be executed currently; if the thread executes the native method, the value in the program counter is undefined.

  Since the size of the space occupied by the data stored in the program counter will not change with the execution of the program, OutOfMemory will not occur for the program counter.

2. Java stack

  The Java stack is also called the virtual machine stack (Java Virtual Machine Stack), which is what we often call the stack, which is similar to the stack in the data segment of the C language. In fact, the Java stack is the memory model of Java method execution. Why do you say that? Let's explain why.

  Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池(运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息。当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。因此可知,线程当前执行的方法所对应的栈帧必定位于Java栈的顶部。讲到这里,大家就应该会明白为什么 在 使用 递归方法的时候容易导致栈内存溢出的现象了以及为什么栈区的空间不用程序员去管理了(当然在Java中,程序员基本不用关系到内存分配和释放的事情,因为Java有自己的垃圾回收机制),这部分空间的分配和释放都是由系统自动实施的。对于所有的程序设计语言来说,栈这部分空间对程序员来说是不透明的。下图表示了一个Java栈的模型:

  局部变量表,顾名思义,想必不用解释大家应该明白它的作用了吧。就是用来存储方法中的局部变量(包括在方法中声明的非静态变量以及函数形参)。对于基本数据类型的变量,则直接存储它的值,对于引用类型的变量,则存的是指向对象的引用。局部变量表的大小在编译器就可以确定其大小了,因此在程序执行期间局部变量表的大小是不会改变的

  操作数栈,想必学过数据结构中的栈的朋友想必对表达式求值问题不会陌生,栈最典型的一个应用就是用来对表达式求值。想想一个线程执行方法的过程中,实际上就是不断执行语句的过程,而归根到底就是进行计算的过程。因此可以这么说,程序中的所有计算过程都是在借助于操作数栈来完成的。

  指向运行时常量池的引用,因为在方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向运行时常量。

  方法返回地址,当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。

  由于每个线程正在执行的方法可能不同,因此每个线程都会有一个自己的Java栈,互不干扰。

3.本地方法栈

  本地方法栈与Java栈的作用和原理非常相似。区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的。在JVM规范中,并没有对本地方发展的具体实现方法以及数据结构作强制规定,虚拟机可以自由实现它。在HotSopt虚拟机中直接就把本地方法栈和Java栈合二为一。

4.堆

  在C语言中,堆这部分空间是唯一一个程序员可以管理的内存区域。程序员可以通过malloc函数和free函数在堆上申请和释放空间。那么在Java中是怎么样的呢?

  Java中的堆是用来存储对象本身的以及数组(当然,数组引用是存放在Java栈中的)。只不过和C语言中的不同,在Java中,程序员基本不用去关心空间释放的问题,Java的垃圾回收机制会自动进行处理。因此这部分空间也是Java垃圾收集器管理的主要区域。另外,堆是被所有线程共享的,在JVM中只有一个堆。

5.方法区

  方法区在JVM中也是一个非常重要的区域,它与堆一样,是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。

  在Class文件中除了类的字段、方法、接口等描述信息外,还有一项信息是常量池,用来存储编译期间生成的字面量和符号引用。

  在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。

  在JVM规范中,没有强制要求方法区必须实现垃圾回收。很多人习惯将方法区称为“永久代”,是因为HotSpot虚拟机以永久代来实现方法区,从而JVM的垃圾收集器可以像管理堆区一样管理这部分区域,从而不需要专门为这部分设计垃圾回收机制。不过自从JDK7之后,Hotspot虚拟机便将运行时常量池从永久代移除了。

  以上为个人看法和观点,如有不正之处希望谅解并欢迎指正。

  参考资料:

  http://blog.csdn.net/ns_code/article/details/17565503

  http://www.cnblogs.com/sunada2005/p/3577799.html

  《深入理解Java虚拟机》

  《Java虚拟机规范 SE7》

  转载请标明地址:http://www.cnblogs.com/dolphin0520/p/3613043.html

Guess you like

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