Jvm 内存区域

简而言之 JVM 内存区域规范, 分为方法区, 堆内存, 虚拟机栈, 本地方法栈, 程序计数器
- 方法区: 线程共享, 存储已被虚拟机加载的类信息, 常量, 静态变量, 即时编译器编译后的代码等数据;常量池在这里啊; 1.8后被元空间替换
- 堆内存: 保存所有new出来的对象数据, GC的主要战场
- 虚拟机栈: 保存基本变量, 对象引用..
- 本地方法栈: 就是..栈, 不过是调用本地方法的栈
- 程序计数器: 保存线程执行上下文的 唯一不会内存溢出的地方
方法区
Java 1.8 之后使用元空间(MetaSpace)替换1.7之前的方法区(Method Area)实现, 元空间直接使用本地内存,理论上只受本地内存大小限制;
常量池
Class文件常量池 (Class常量池)
class文件是一组以字节为单位的二进制数据流, 在Java代码的编译期间, 我们编写的Java文件就被编译为.class文件格式的二进制数据存放在磁盘中, 其中就包括class文件常量池;
class文件常量池主要存放两大常量: 字面量和符号引用;
class常量池是在编译的时候每个class都有的, 在编译阶段, 存放的是常量的符号引用;
in short 真正意义上的元信息, 存在方法区中, 即使多个class都有相同的字面量, 相当于硬编码在class文件中
运行时常量池
当Java文件被编译成class文件之后, 会生成上面的class文件常量池, JVM在执行某个类的时候, 必须经过加载, 链接(验证, 准备, 解析), 初始化的步鄹 运行时常量池则是在JVM将类加载到内存后,就会将class常量池中的内容存放到运行时常量池中, 也就是class常量池被加载到内存之后的版本, 是方法区的一部份
在解析阶段, 会把符号引用替换为直接引用, 解析的过程会去查询字符串常量池, 也就StringTable, 以保证运行时常量池所引用的字符串与字符串常量池中是一致的;
运行时常量池相对于class常量池一大特征就是具有动态性, Java规范并不要求常量只能在运行时才产生, 也就是说运行时常量池的内容并不全部来自class常量池, 在运行时可以通过代码生成常量并将其放入运行时常量池中, 这种特性被用的最多的就是String.intern();
in short 这里存字符串常量其实是引用, 指向字符串常量池
字符串常量池
在JDK6.0及之前版本, 字符串常量池存放在方法区中, 在JDK7.0版本以后, 字符串常量池被移到了堆中了;
在JDK6.0中, StringTable的长度是固定的, 长度就是1009 在JDK7.0中, StringTable的长度可以通过参数指定;
in short 正真存字符常量的地方, 1.6在方法区, 1.7以后在堆中 再议String-字符串常量池与String.intern()
堆内存
略..
虚拟机栈
略..
本地方法栈
略..
程序计数器
略..
JVM 如何访问对象?
实例对象数据
在 HotSpot虚拟机中, 对象在内存中存储的布局分为三块区域:对象头,实例数据, 和对齐填充数据;
对象头
对象头包括如下两部分信息:
MarkWord: 用于存储对象自身的运行时数据, 如哈希码, GC分代年龄, 锁状态标志, 线程持有的锁, 偏向线程ID, 偏向时间戳等; 为了在极小空间内存储更多的信息, 它被设计成了一个非固定的数据结构, 根据对象的状态来复用自己的存储空间
实例数据
是对象真正的有效数据, 也就是代码中所定义的各种类型的字段内容, 无论是从父类继承还是子类记录的都必须进行存储;
对齐填充数据
对齐填充并不是必然存在的, 也没有其它的意义, 仅仅是占位符的作用, 因为HotSpot虚拟机的自动内存管理系统要求对象地址必须是8的整数倍, 当实例数据没有对齐时, 就需要对齐填充来进行补齐
访问方式
使用句柄池
在Java堆中专门划分出一部分内存作为句柄池,reference 中存储的是对应对象的句柄地址, 而句柄池中包含了对象实例数据和类型数据具体的地址信息
直接指针访问
直接指针访问,reference 中直接存储的是对象地址
两种方式的比较
使用句柄池来访问最大的好处就是reference 中存储的是稳定的句柄地址,在对象被移动(垃圾收集时整体空间位置)时只会改变句柄中的实例数据指针, 而reference不需要任何改变;
使用直接指针访问最大的好处就是快, 节省了一次指针定位的时间开销, 由于对象访问在java中非常频繁, 积少成多, 节省这样的开销效益非常可观;
主要虚拟机HotSpot采用直接指针访问, 但是许多其他语言和框架使用句柄这种思想也非常常见;
Arthas 工具
Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。
https://arthas.aliyun.com/doc/
TODO