程序计数器
线程私有,当前线程锁执行的字节码的行号指示器无OutOfMemory错误虚拟机栈
线程私有,java方法执行时会创建栈帧,存储 局部变量表,操作数栈,动态链接和方法出口等信息局部变量表存放各种编译器可知的基本数据类型boolean、byte、char、short、int、float、long、double、对象引用(地址)和returnAddress(下一条字节码指令地址)局部变量表的内存空间在编译器分配完成,方法运行期间不会改变其大小。本地方法栈
虚拟机使用本地Native方法服务有的虚拟机把这部分与虚拟机栈合并Java堆
线程共享,存放对象实例,几乎所有的对象实例以及数组都要在堆上分配垃圾回收的主要区域,GC堆可以处在物理不连续的空间上,但是逻辑上要连续方法区(也叫堆-永久代)
线程共享,存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码
运行时常量池:存放编译器生成的各种字面量和符号引用
遇到一条New指令后,先去常量池检查这个类是否已经被加载,如果没有,则执行类加载
对象所需内存的大小在类加载后就可以完全确定(通过类元数据信息),然后将同等大小的内存从堆中划分给对象。
分配方法:
规整内存:指针碰撞不规整内存:空闲列表分配同步:
CAS+失败重试本地线程分配缓冲对象内存 = 对象头 + 实例数据 + 对齐填充
对象头一般包括两部分信息:
存储对象自身的运行时数据(hashCode,GC Age, 锁状态等) 一个字长大小,也叫“MarkWord”,非固定结构,根据对象的不同状态,存储不同含义的数据类型指针,对象指向类元数据的指针。如果是数组,还需要记录数组长度实例数据:类中所定义的各种类型的字段内容
对齐填充:HotSpot要求对象起始地址必须是8字节的整数倍,对象的大小必须是8字节的整数倍。
通过操作栈上的Reference数据来操作堆上的对象,如何实现Reference:
句柄:二层索引,稳定 指针:一层索引,快速高效程序计数器和虚拟机栈、本地方法栈随线程生存消亡,内存分配回收相对确定,但是堆上内存就复杂的多,需要设计垃圾回收算法进行回收。
标记-清除算法
标记所有需要清除的对象,然后再统一回收存在效率问题和空间问题(内存碎片)复制算法
内存对半分,用完一半,回收时,将存活对象复制到另外一半,顺序排列简单高效,但是内存容量缩小一个大的Eden空间和两个小的survivor空间,每次使用Eden和一个survivor(from),在回收时,将其中还存活的对象一次性复制到另外一个survivor(to)中,当survivor(to)空间不够时,依赖其他内存进行分配担保标记-整理算法
标记需要清理的对象,然后存货对象向内存一端移动分代收集算法
Java堆划分为新生代和老年代,新生代存储新分配的对象,老年代存放存活周期大和内存空间大的对象新生代对象代谢频繁,使用复制算法,老年代存活率高,使用另外两种算法。新闻热点
疑难解答