[Java]《深入理解Java虚拟机》学习笔记-Java内存区域与内存溢出异常

一、运行时数据区域

1、程序计数器(Program Counter Register)

线程私有,当前线程所执行的字节码的信号指示器。如果线程正在执行Java方法,计数器记录的是那么正在执行的虚拟机字节码指令的地址;如果线程正在执行Native方法,计数器值则为空。此内存区域是Java虚拟机规范中唯一一个没有规定任何OOM的区域

2、Java虚拟机栈(Java Virtual Machine Stacks)

线程私有,生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法执行时会创建一个栈帧(stack frame)用于储存局部变量表、操作数栈、动态链接、方法出口等信息。一个方法的执行到结束,即代表Stack Frame的入栈和出栈。

大多数人把Java内存分为堆内存和栈内存,这个所指的栈就是指的这里的虚拟机栈中局部变量表部分,存放了编译期可知的各种基本数据类型(boolean、byte、char、int、float等)、对象引用(reference类型,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)。当进入一个方法时,所需要分配的局部变量空间大小是确定的,不会随运行而改变。

这个区域有两种异常:StackOverFlow-请求的栈深度超过虚拟机所允许的深度;OutOfMemoryError-可扩展虚拟机扩展时无法申请到足够的内存。

3、本地方法栈(Native Method Stack)

线程私有,与虚拟机栈发挥的作用是相似的,而虚拟机栈的作用是为Java方法服务,而本地方法栈是为Native方法服务。同时也有两种异常:StackOverFlow、OutOfMemoryError

4、Java堆(Java Heap)

线程共享,对于大多数应用,Java堆是内存中最大的一块。用来存放对象实例,几乎所有对象实例都在这分配内存。不需要连续的内存和可以选择固定大小或者可扩展。

Java Heap是垃圾收集器管理的主要区域,经常被称为CG堆(Garbage Collected Heap)。

内存回收角度:新生代和老生代;再细致点的有Eden空间、From Survivor空间、To Survivor空间等。

内存分配角度:划分出多个线程私有的分配缓冲区。

进一步划分是为了更好地回收内存,或者更快地分配内存。

Java堆无法给新对象分配内存时,会抛出OutOfMemoryError

5、方法区(Method Area)

线程共享,用于储存已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。不需要连续的内存和可以选择固定大小或者可扩展,而且可以选择不实现垃圾收集。

当方法区无法满足内存分配需求时,会抛出OutOfMemoryError。

6、运行时常量池(Runtime Constant Pool)

是方法区的一部分,用于保存class文件中描述的符号引用,具备动态性,运行时可以将新的常量放入。

受到方法区内存限制,常量池无法再申请到内存时报OutOfMemoryError

二、HotSpot虚拟机对象探秘

1、对象的创建

类加载检查:检查该对象的类是否已经被加载、解析、初始化过,如果没有则先进行类加载操作。

分配内存:如果内存规整则使用“指针碰撞”(一边是空闲一边是使用,指针移动对象大小相等距离)分配,否则一般使用“空闲列表”(内存不规整,那么维护一张空闲表)分配,具体看垃圾回收器是否带有整理(Compact)空闲内存功能。

同步处理:1、CAS配上失败重试;2、本地线程分配缓冲(TLAB)

初始化:初始化0值,保证代码可不赋值就是用。

对象头设置:这个对象是哪个类的实例、如何找到类的元数据信息、哈希码、GC分代年龄信息等即为对象头。

对象的方法:即按照程序员的意愿进行初始化。

2、对象的内存布局

对象头(Header):一部分称为Mark Word,包含哈希码、GC分代年龄、锁状态标志等等,采用压缩存储,压缩到虚拟机位数(32位/64位);另一部分为类型指针,指向它的类元数据,用于对象的访问定位,非必需,看虚拟机的具体实现。

实例数据(Instance Data):对象真正储存的有效信息,具体其成员字段的内容,包含父类。分配策略参数,相同宽度字段总是分配在一起。

对齐填充(Padding):不是必然存在,只是占位符,只有前两者加起来非8的倍数时才会有。

3、对象的访问定位

通过句柄访问对象:当java虚拟机GC移动堆对象时,并不需要修改reference,只需修改句柄对象的实例数据指针

通过直接指针访问对象:加快了对象访问速度,比间接访问少一次对象实例数据的访问,HotSpot则采用的这种访问方式。

三、OutOfMemoryError异常实战

1、Java堆溢出:不断创建对象

2、虚拟机栈和本地方法栈溢出:定义大量本地变量。

3、方法区和运行时常量池溢出

4、本机直接内存溢出

发表评论

电子邮件地址不会被公开。 必填项已用*标注