jvm 运行时数据区-爱代码爱编程
对象的内存布局
HotSpot 虚拟机,对象在 堆内存 中的存储布局分为
对象头 header, 实例数据 Instance Data, 对齐填充 Padding
对象头 header
Mark Word - 对象运行时数据
哈希码 HashCode, GC分代年龄, 锁状态标志, 线程持有的锁,偏向线程ID,偏向时间戳等
类型指针 - 对象所属的类型信息
数组长度 - 如果对象是数组的话
实例数据 Instance Data
class 里的字段,父类定义的字段在子类定义的字段前面
HotSpot虚拟机可配置压缩字段空间,子类较窄的字段可以插入父类变量的空隙之中
+XX: CompactFields = true (默认 true)
对齐填充 Padding
HotSpot 虚拟机内存管理系统 对象起始地址是8字节的整数倍,对象头已经设计成8字节的整数倍,实例数据没有对齐的部分通过对齐填充来补全
对象的访问
java 程序通过栈上的 引用(reference) 来访问堆上的具体对象, 一般是通过 句柄 或 直接指针 来访问
句柄
java 堆中划分一块内存做 句柄池,栈中的 reference 存储的是对象的句柄地址,
句柄中包含了对象 实例数据 与 类型数据 的地址信息
直接指针
栈中的 reference 存储的是对象地址,对象里放置了类型数据的地址信息
----------------------------------------------------
JVM 内存模型
内存分为 堆,方法区,栈,本地方法栈,程序计数器
-------------------------
堆
线程共享,用来存放对象实例及数组
OutOfMemoryError - 堆不够内存完成实例分配,并且堆无法再扩展时
1.通过参数让虚拟机在堆内存溢出的时候 Dump 出堆转储快照
-XX: +HeapDumpOnOutOf-MemeryError
2.通过内存映像分析工具(如 Eclipse Memory Analyzer),对 Dump
出来的堆转储快照进行分析,确认导致 OOM 的对象是否有必要,
如果是内存泄露(memory leak), 修改代码,及时释放
如果是内存溢出(memory overflow), 一方面检查堆大小配置(-Xmx -Xms),
看是否有调大的空间,另一方面检查代码,是否有某些对象没有及时释放,存储结构不合理的情况
-------------------------
方法区
线程共享,类型信息(类名,访问修饰符,字段描述,方法描述,常量池),常量,静态变量,即时编译器编译后的代码缓存等数据
jdk 1.7之前 Perm Space 永久代, JVM 自己的内存
jdk 1.8之后 元空间, 直接内存
OutOfMemoryError - 运行时产生大量的类填满方法区
运行时常量池
class 文件里有一项信息是 常量池表,用于存放编译期生成的各种字面量与符号引用
在类加载的时候,存放到方法区的运行时常量池
运行时也可以把新的常量放入池中,如 String.intern()
hotSpot 虚拟机 jdk6 以前 是方法区的一部分,和方法区一样放在永久代
-XX:PermSize
-XX:MaxPermSize
OutOfMemoryError - 当 运行时常量池 无法满足新的内存分配需求时
hotSpot 虚拟机 jdk7 把 运行时常量池 移到了 java 堆中
-Xmx
OutOfMemoryError - 当 运行时常量池 无法满足新的内存分配需求时
-------------------------
栈
Java 虚拟机堆栈,跟线程对应,用来存储栈帧
栈帧在方法被调用的时候创建,用来存储局部变量表,操作数栈,动态连接和方法的返回地址等信息,
每个方法从被调用到执行完毕,都对应着虚拟机栈中的一个栈帧从入栈到出栈的过程
-------------------------
本地方法栈 - 与栈类似
HotSpot 虚拟机并不区分栈与本地方法栈
栈为虚拟机执行 java 方法服务
本地方法栈为虚拟机执行本地方法服务
-Xss 栈内存容量
局部变量表 存着 基本数据类型 和 对象引用
StackOverflowError
当线程请求的栈深度大于虚拟机所允许的栈深度时
OutOfMemoryError
当栈无法申请到足够的内存时
-------------------------
程序计数器
线程私有,当前线程所执行的字节码的行号指示器
----------------------------------------------------