本章将从概念上介绍Java虚拟机内存的各个区域,讲解这些区域的作用、服务对象以及其中可能产生的问题,这是翻越虚拟机内存管理这堵围墙的第一步。
运行时数据区域
程序计数器
是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。
作用:分支、循环、跳转、异常处理、线程恢复等基础功能需要依赖这个计数器来完成。
Java虚拟机栈
是线程私有的,与线程生命周期相同。描述的是Java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧。
作用:用来存储局部变量表、操作数栈、动态链接、方法出口等
使用场景:每一个方法从调用直到执行完成的过程,就对应着一个栈帧在虚拟机入栈出栈的过程。
本地方法栈
与虚拟机栈类似,为Native方法服务。
常见异常:StackOverflowError、OutOfMemoryError异常
Java堆
是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”。
特点:
- Java虚拟机所管理的内存中最大的一块
- 被所有线程共享的一块内存区域
- 在虚拟机启动时创建
作用:存放对象实例
分类:
- 粗分:新生代和老年代
- 细分:Eden空间、From Survivor空间、To Survivor空间
扩展:-Xmx和-Xms
常见异常:OutOfMemoryError异常
方法区
与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的。
作用:存储类信息、常量、静态变量、即时编译器编译后的代码等数据。
常见异常:OutOfMemoryError异常
运行时常量(归属方法区)
是方法区的一部分。
作用:用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
特征:具备动态性,如:String类的intern()方法
常见异常:OutOfMemoryError异常。
直接内存(堆外内存)
不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。
使用场景:NIO(基于通道与缓冲区的IO方式)->分配堆外内存(通过Native函数库)->通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。
常见异常:OutOfMemoryError异常。
HotSpot虚拟机对象探秘
对象的创建
虚拟机遇到new指令->检查加载类过程->为新对象分配内存->将分配到的内存空间都初始化为零值->对对象进行必要的设置。
内存分配方式:
- 指针碰撞(Java堆内存绝对规整的)
- 空闲列表(Java堆内存不规整)
- 依赖关系
- 内存分配方式->Java堆是否规整->采用的收集器是否带有压缩整理功能。
存在问题:
- 虚拟机对象创建是非常频繁的?
- 并发情况下无法保证线程安全?
解决方案:
- 对分配内存空间的动作进行同步处理(采用CAS配置失败重试的方式保证更新操作的原子性)
- 把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(TLAB)。配置参数:-XX:+/-UserTLAB
对象的内存布局
对象头
存储对象自身的运行时数据(HashCode、GC分代年龄、锁状态标志等。实例数据
- 存储顺序受到虚拟机分配策略参数和字段在Java源码中定义顺序的影响。
- 默认分配策略:longs/doubles->ints->shorts/chars->bytes/booleans->oops
- 对齐填充
由于HotSpotVM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,因此当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。
对象的访问定位
Java程序需要通过栈上的reference数据来操作堆上的具体对象。
使用句柄
直接指针
实战:OutOfMemoryError异常
Java堆溢出
配置:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
解决区域异常步骤:
- 通过内存映像分析工具(分析是内存泄漏||内存溢出)
- 内存泄漏:通过工具进一步找出泄漏对象到GCRoots的引用链
- 内存溢出:
- 检查虚拟机堆参数(-Xmx和-Xms)
- 代码检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗
虚拟机栈和本地方法栈溢出
配置参数:-Xss(-Xoss参数无效)
方法区和运行时常量池溢出
配置参数:-XX:PermSize=10M -XX:MaxPermSize=10M
异常场景:
- 在经常动态生成大量Class的应用中,需要特别注意类的回收状况
- CGLib字节码增强和动态语言
- 大量JSP或动态产生JSP文件的应用
- 基于OSGI的应用
本机直接内存溢出
配置参数:-XX:MaxDirectMemorySize(不配置默认与Java堆最大值一样)
特征:在Head Dump文件中不会看见明显的异常