JVM复习-内存区域与对象创建

JVM复习

基于JDK1.7的研究

一、Java内存区域与内存溢出

在这里插入图片描述

  • 程序计数器

    指示当前线程所执行的字节码的行号,编译字节码执行的命令,进而程序才能一步步的执行下去。

  • Java虚拟机栈

    线程私有,生命周期与线程相同。

    每个方法在执行时会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等。方法从调用到执行完成的过程中,就饿对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

    **局部变量表:**存放了编译期间各基本数据类型、对象引用和returnAddress类型。其所需要的内存空间在编译期间完成分配,所以在方法运行期间是不会改变局部变量表的大小。

  • 本地方法栈

    与虚拟机栈类似,不同的是本地方法栈是为jvm调用Native方法服务。

  • Java堆

    线程共享,存放对象实例。堆可以存在在物理上不连续,只要逻辑上连续就行。(GC在后面讲)

  • 方法区

    线程共享,用于存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

  • 运行时常量池

    方法区的一部分,存放Class文件在编译期间生产的各种字面常量和符号引用。Java中并非预置在Class文件中的常量池才会被放入常量池区。在运行期间也可以将新的常量放入该区域,如String类的intern()方法

  • 直接内存

    我理解的是为了方便JVM在Java堆和Native堆中来回复制数据设置的缓冲区。直接内存并不是JVM运行时数据区的一部分,这是一种基于通道和缓冲区的I/O方式。可以通过一个存储子啊Java堆中DirectByteBuffer对象作为这块内存的引用进行操作。

二、对象的创建

JVM接受到一个new的指令是,首先会去常量池中寻找该类的符号引用,然后检察这个符号引用代表的类是否已经加载、解析和初始化过。如果没有则先执行类加载过程。

  • 空间划分

    通过类接在的检查后,JVM为该对象分配内存(内存大小在类加载完后就确定了)。若Java堆的空间是规整连续的采用的分配算法是“指针碰撞”,直接移动与对象大小相同的距离指针分配内存。否则采用“空闲列表”分配,对于堆空间非连续的,用一张空闲记录表记录当前空闲的内存块,在为对象分配内存的时候,从空闲表中找到合适的空间进行分配,同时更新空闲表。

    内存分配完后,JVM将分配到内存的空间全都初始化为零,最后再执行方法进行我们想要的初始化对象

  • 对象的内存布局

    在HotSpot虚拟机中,对象在内存中分为:对象头+实例数据+对齐填充。

    对象头:包含了两部分信息,一部分用于存储对象自身的运行时数据(哈希吗、GC年龄代、锁状态、线程持有的锁等);另一部分是类型指针,即对象指向他的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。若对象是个数组,对象头中还需有一块用于记录数组长度的数据。

    实例数据:是对象真正存储的有效信息

    对齐填充:对象的大小必须是8的整数倍,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。