A series JVM (Java memory area and object creation).

A, JVM memory area

Heap - Heap

Threads share, JVM largest piece of memory, the sole purpose of this memory is to store the object instance, Java heap is the main area managed by the garbage collector, and therefore often also referred to as "GC heap" (Garbage Collected Heap), by -Xms -Xmx and parameters to control the size of the region.

The method area - Method Area

Threads share, class information (version, fields, methods, and interface description information) which is used to store the virtual machine has been loaded, a constant, static variables, the real-time data such as the code compiler.

In the JDK 1.7, methods are described heap area (Heap) of a logic portion, which region is also known as Non-Heap (non-stack), the HotSpot virtual machine immortalized Generation (Permanent Generation) in the region of 1.7 to implement the method so the garbage collector can manage the Java heap like this as part of memory management, work can be dispensed with memory management code written specifically for the method area, and therefore often been immortalized on behalf of the district and equivalent methods, and therefore eternal generation parameters (- XX: PermSize, -XX: MaxPermSize) method also limits the size of the memory area.

In JDK 1.8, in order to reduce the memory area of ​​the overflow method and the subsequent merger of the HotSpot and JRockit, HotSpots canceled permanent Generation (-XX: PermSize, -XX: MaxPermSize was dumped parameter), element space (Metaspace) board stage, the method area exists in the element space, at the same time, yuan and heap space is no longer continuous, but is present in the local memory (native memory), this means that as long as enough local memory, it does not appear like the permanent generation "java.lang .OutOfMemoryError: PermGen space "this error, by default roadway space unlimited use local memory, by limiting the size of the yuan space (-XX: MaxMetaspaceSize: MetaspaceSize, -XX).

Runtime constant pool - Runtime Constant Pool

Thread content sharing, file storage, including Class constant pool (the part after the class into the compilation) and translation out of the direct reference.

Class constant pool contents include:

For the runtime constant pool, Java Virtual Machine Specification do not require any details of the different providers of virtual machines can be realized in accordance with their own needs to achieve this memory area. An important feature of runtime constant pool file relative to Class constant pool is equipped dynamic, that is not preset into the constant pool file content Class method to enter the zone runtime constant pool, during operation it is also possible to put a new constant into the pool, the more common such as intern String class () method.

VM stack / native method stacks

Thread private life cycle with the same thread, Java memory model is the method of execution described: simultaneous execution of each method will create a stack frame (Stack Frame) for storing local variable table, the operand stack, dynamic linking, for export and other information. Each method call from execution until the process is completed, it corresponds to a push to the stack frame of a process stack.

Local variable table stored for various compilers basic types of known (boolean, byte, char, short, int, float, long, double), object reference (reference type), returnAddress type (address pointing to a byte code execution ). Wherein the long and double length of 64-bit data will occupy two local variable space (Slot). Required for completion of the local variable table memory space allocated during compilation, during operation of the method does not change the size of the local variable table.

VM stack and native method stacks difference however is the virtual machine execution stack for the Java virtual machine service method, and native method stacks of virtual machines are Native method service. HotSpot virtual machine directly to the virtual machine and native method stacks into one stack. May be provided by the virtual machine -Xss stack size parameter, -Xoss native method stacks parameter set (parameter does not take effect on the HotSpot VM).

Program Counter

Thread private, a small memory space, it can be seen as an indicator byte-code line number of the current thread of execution, this memory area is only one case does not provide for any area OutOfMemoryError in Java Virtual Machine Specification, therefore the region has become an area of ​​least concern programmer.

直接内存 - Direct Memory

线程私有,并不是虚拟机运行时数据区的一部分,也不是 Java 虚拟机规范中定义的内存区域。Java NIO (New Input/Output)是一种基于通道(Channel)与缓存区(Buffer)的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。

该区域也可能导致内存溢出,一个明显的特征是在 Heap Dump 文件中不会看见明显的异常。因此,服务器管理员在根据实际内存配置虚拟机参数时,需要考虑到直接内存需要的空间,可以通过 -XX:MaxDirectMemorySize 来指定直接内存的大小,如果不指定,则默认与 Java 堆的最大值(-Xmx)一样。

二、Java 对象创建

接下来看看我们平常的一个 new 操作在 JVM 中又是怎样一种过程呢?(讨论的是普通 Java 对象,不包括数组和 Class 对象等)。

1. 栈空间分配

当执行 new 操作的时候,首先进行的是在Java 栈的局部变量表中分配一个对象引用(reference 类型,不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄)。

2. 类加载检查

JVM 检查这个对象是否能在常量池(指的是 Class 文件常量池)中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,那必须先执行类加载过程(静态块、静态变量、静态方法加载进静态方法区等操作)。

3. 分配内存

对象所需的内存大小在类加载完成后便可完全确定,因此为对象分配内存空间其实就是怎样把一块确定大小的内存从 Java 堆中划分出来。一般有两种分配方式:

指针碰撞
Java 堆中的内存是绝对规整的,所有用过的内存放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离。

空闲列表
Java 堆中的内存并不是规整的,虚拟机维护了一个列表,记录了哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录。

内存分配的方式由 Java 堆是否规整决定, Java 堆是否规整又是由所采用的垃圾收集器是否带有 compact(压缩整理)功能决定。比如 Serial、ParNew 等基于 stop-and-copy 算法的收集器就具有 compact 功能,而 CMS 这种基于 mark-and-sweep 算法的收集器就不具有 compact 功能。

虚拟机默认使用 CAS 配上失败重试的方式保证内存分配操作的原子性,可通过 -XX:+/-UseTLAB 指定使用 TLAB(Thread Local Allocation Buffer, 本地线程分配缓冲);

HotSpot VM 的自动内存管理系统要求对象起始地址必须是 8 字节的整数倍,换句话说,就是对象的大小必须是 8 字节的整数倍。因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

4. 初始化工作

接下来虚拟机加载非静态块、非静态方法、非静态变量,并将分配到的内存空间都初始化零值(引用类型初始化为 null,int 类型初始化为 0 等),这一步操作保证了对象的实例字段在 Java 代码中可以不赋初始值就能直接使用。

5. 对象头设置

接下来虚拟机将进行对象头的填充设置,HotSpot 虚拟机的对象头包括一般两部分信息:

第一部分(Mark Word)
存储对象自身的运行时数据,如哈希码、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在 32 位和 64 位虚拟机(未开启压缩指针)中分别为 32bit 和 64 bit。

第二部分(类型指针)
对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。但是并不是所有的虚拟机实现都必须在对象数据上保留类型指针,比如通过句柄访问。下文会提到。

如果对象是一个数组,那么对象头中还必须有一块用于记录数组长度的数据,因为虚拟机从数组的元数据中无法确定数组的大小。

6.构造器工作

如果有父类,则父类按上述流程保证被加载。

7. 对象的访问定位

现在堆中的对象实例有了,栈中的 reference 也有了,怎么将两者关联在一起呢?目前主流的方式有使用句柄和直接指针两种:

使用句柄
Java 堆中划分出一块内存作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象的实例数据与类型数据各自的具体地址信息。它的优点就是 reference 存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而 reference 本身不需要修改。

直接指针
reference 中存储的直接就是对象地址。它的好处就是速度更快,节省了一次指针定位的时间开销。


HotSpot VM 使用的直接指针进行对象访问。

Guess you like

Origin www.cnblogs.com/jmcui/p/11875858.html