新冠肺炎疫情,假期延长+在家办公=3周看完《深入理解JVM虚拟机》:这本很早之前就在我的待办事项里的书。
JVM虚拟机有虚拟机规范和多种商业虚拟机实现版本,本书主要以HotSpot为例进行讲解(HotSpot本身用C++/C语言实现)
一、 自动内存管理机制
运行时的内存分区包括:
1)程序计数器:线程私有区域,指示当前线程执行的字节码行号;
2)栈:存放栈帧(方法模型),包含方法的操作数、局部变量、返回结果等;方法的调用、返回对应入栈、出栈。线程调用方法过深,超过最大深度,触发StackOverflow;若栈内存允许动态扩展,但超过了最大内存,则触发OutOfMemory异常。配置参数:-Xss
3)本地方法栈:类似栈,对应本地native方法(不是由java语言实现,而是由例如c/c++实现)。配置参数:-Xoss
4)堆:存放对象和数组,空间大,线程间共享。垃圾回收的主战场,GC大多采用分代收集算法,相应的堆分为老年代和新生代。堆内存可以不连续(但堆中对象内存空间需要连续);超过内存大小时,触发OutOfMemory异常。配置参数:-Xms/mx,二者相等则避免堆自动扩展;-Xmn配置新生代。
5)方法区:存放编译后的方法代码、类信息(类名、访问修饰符、字段描述、方法描述等)、常量、静态变量。线程间共享;垃圾回收较少,主要针对常量回收和类卸载,又称永久代。方法区包括常量池(String.intern-查看常量池是否存在相同字面值,存在则复用常量池中的常量);配置参数:MaxPermSize/PermSize
6)直接内存:NIO使用Native函数分配的堆外内存,通过堆上的DirectByteBuffer对象引用从而进行操作。配置参数:MaxDirectMemorySize,默认值为-Xmx
二、对象
1. 创建:当虚拟机遇到new指令,执行下列步骤:
1)检查指令参数(类名)能否定位到常量池中的类,类是否已被加载、解析、初始化,没有则执行类加载。
2)分配内存:对象需要连续的内存空间。所需内存大小在类加载后可确定;根据堆是否规整(GC是否具有压缩整理功能)来决定采用指针碰撞或空闲列表分配方式。指针碰撞:假设堆规整的分为用过和没用过的内存,指针指示分界点,那么分配内存就是把指针向空闲区移动所需分配大小;空闲列表:假设堆不规整,通过列表指示可用内存,找到一块足够的内存分配给新生对象,同时更新空闲列表。本地线程分配缓冲TLAB(Thread Local Allocation Buffer)用于解决线程安全问题,在堆中为各线程划分区域,线程需要分配内存时优先在TLAB分配,TLAB用完后结合同步机制。配置参数:-XX:+/-UseTLAB
3)将分配的内存初始化。保证对象实例不赋初值时,程序能访问到零值。
4)设置对象头,包括对象运行时数据:哈希值、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、时间戳;类型指针:对象指向类的元数据的指针
5)虚拟机执行构造函数,按照程序员的意愿进行初始化。
2. 对象的内存布局
包括:对象头,实例数据和对齐填充三部分。其中实例数据存储代码中定义的字段值,存储顺序由虚拟机分配策略(相同宽度的字段分配在一起)和字段定义顺序决定。由于虚拟机要求对象起始地址是8字节的整数倍,因此需要填充字段。需要注意的是:方法属于类,而不是对象,因此存储在方法区。
3. 对象的访问定位
程序根据栈上的reference操作堆上的对象。两种引用方式:
1)句柄:划分一块堆内存作为句柄池,句柄包括对象和类的地址;reference指向句柄。好处是对象被移动时(GC会频繁移动对象),reference不需要改变。
2)直接指针:reference存储对象地址,对象内存中包含类地址。好处是速度快,节省一次指针定位开销。
三、常见的OOM异常
1. 堆溢出(常见)
错误提示:java heap space。
解决方式:使用内存映像分析工具分析到底是出现了内存泄漏还是内存溢出;如果是内存泄漏,查看泄漏对象到GC root到引用链,定位泄漏代码的位置。如果是内存溢出,查看虚拟机当前设置的堆参数,与物理机内存比较是否可以调大,并且从代码层面查找是否对象持有时间过长可以优化。
2. 栈和本地方法栈溢出
单线程(罕见):栈帧太大/栈空间太小触发StackOverflow异常。栈最大深度通常在1000-2000,能满足多数应用场景。
多线程(OOM):OS分配给进程的内存有限。栈内存=进程内存总量-最大堆内存-最大方法区内存=单个线程栈内存*线程数。解决方案包含:提高进程内存总量(通过使用64位);减少最大堆内存;减少最大方法区内存;减少线程数;减少栈容量等。
3. 方法区和运行时常量池溢出
诊断方式:Perm Gen space
4. 直接内存溢出
诊断方式:Heap Dump文件小,无明显异常,程序中直接/间接使用了NIO。
网友评论