目录
前言
一、运行时数据区域
1.程序计数器(Program Counter Register)
2.虚拟机栈(VM Stack)
3.本地方法栈(Native Method Stack)
4.Java堆(Heap)
5.方法区(Method Area)
二、直接内存
1.DirectByteBuffer
2. *** 作
3.异常
三、对象
1.创建对象
2.内存布局
3.访问定位
前言
参考周志明的《深入理解Java虚拟机》,进行简单的总结记录。本小结总结了《深入理解Java虚拟机》第二章内存区域。
一、运行时数据区域 1.程序计数器(Program Counter Register)
线程私有。针对方法内部:字节码调用。可以看作是当前线程执行的字节码的行号指示器。控制着程序运行的顺序、分支、循环、跳转等等。执行Java方法:记录的是字节码指令的地址。执行Native方法:记录的是空(undefined)。内存中唯一没有OOM的区域。 2.虚拟机栈(VM Stack)
线程私有。描述的是Java方法执行时线程的内存模型,直观上看就是debug调试的堆栈信息。一个方法从调用到被执行完毕,就是对应一个栈帧从入栈到出栈的过程。栈帧保存了局部变量表、 *** 作数栈、动态链接、方法出口等信息。异常:线程请求栈的深度超过虚拟机允许深度,发生StackOverFlowError;虚拟机栈动态扩展时无法申请到内存,发生OutOfMemoryError。 3.本地方法栈(Native Method Stack)
与虚拟机栈类似,只不过是为Native方法服务。 4.Java堆(Heap)
线程共享虚拟机中很大的一块内存,保存对象的实例。垃圾回收的主要区域。异常:堆内无法实例分配,且堆无法扩展,发生OOM。 5.方法区(Method Area)
线程共享堆的一个逻辑部分,别名:Non-Heap存储内容:虚拟机加载的类、常量、静态变量、即时编译器编译后的代码。HotSpot虚拟机对方法区的实现叫做永久代,jdk1.8中,移到了元空间(metaSpace)。方法区内还有一块内存叫做运行时常量池,存储已被加载的class文件中的常量池表(Constant Pool Table)。当常量池无法申请到内存时,发生OOM。 二、直接内存 1.DirectByteBuffer
占用堆外内存,是Native直接调用的机器内存。JVM会在DirectBuffer上直接使用本地IO *** 作(Native I/O Operations)。好处:避免额外的数据复制,提高IO效率。减低GC的工作量。场景:需要容量较大且长期使用的缓存。需要测试确定是否能获得性能提升。MappedByteBuffer:继承DirectByteBuffer,可以将文件内容映射到内存。 2. *** 作
通过存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行 *** 作。DirectBuffer一般在FullGC时被回收。 3.异常
不受参数-Xmx参数控制,设置大小:-XX:MaxDirectMemory=512M受物理内存、SWAP分页限制。如果堆内存Xmx满了,物理内存和分页也用完了,则无法继续申请直接内存(OOM)。 三、对象 1.创建对象
内存划分:指针碰撞和空闲列表。
指针碰撞:内存规整,只需要移动指针来分配空间。空闲列表:内存不规整,虚拟机需要维护哪些空间是空闲的,找到足够的空间分配。如何选择:取决于Java堆是否规整,Java堆是否规整又取决于GC是否带有空间压缩整理的能力。 2.内存布局
对象头Header:Mark Word+Class pointer+array length
Mark Word:存储对象自身的运行时数据,如hashcode,gc分代年龄、锁标志等。Class pointer:类型指针,指向它的类元数据,JVM通过这个指针确定对象时哪个类的实例。array length:如果对象是数组,那么对象头还需要额外的空间存储数组的长度。实例数据:对象真正存储的有效数据。对其填充:非必须,占位功能,因为hotspot自动内存管理要求对象起始地址必须是8字节的整数倍,如果不是,则用它填充。 3.访问定位
句柄池:Java堆中划出一块内存存储句柄池,引用存储的句柄池的地址,而句柄中存储了对象实例数据和到对象类型数据的指针。
优点:稳定,当对象移动(因为gc等)时只需要修改句柄中到对象实例的指针即可。缺点:两次寻址直接指针:reference中存储的就是对象的地址,此时对象中就要存储到对象类型数据的指针了。(HotSpot主要使用)
优点:访问对象比较快。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)