整个虚拟机结构
虚拟机由以下四个部分组成。类加载器、执行引擎、native接口、运行时数据区(堆栈内存这些)这里借用网上的一个图就可以一目了然
- 类加载器,主要复制加载磁盘中的class文件,将文件通过类加载器加载、验证、准备、解析、初始化到内存中。
- 运行时数据区,就是我们常见的八股文,堆了栈了相关的
- 执行引擎,执行引擎主要用来执行Java生成的字节码,解析/编译成各种cpu 所能执行的二进制指令。简单来说,JVM 中的执行引擎充当了将高级语言翻译为机器语言的译者。
运行时数据区
- 线程共享
- 堆
- 存放new出的对象
- 静态变量的值
- 字符串常量池
- 方法区、永久代(JDK1.8后改为元空间,在直接内存中)
- 存放常量
- 字节码文件
- 线程不共享
- 栈
- 本地方法栈
- 存放native方法(C语音实现的底层方法)
- 虚拟机栈
- 存放临时变量
- 程序计数器
- 每个线程一块内存,指向当前正在执行的字节码的行号。
- 如果当前线程是native方法,则其值为null。
JVM内存结构易错点
- 静态变量存在堆中,变量引用存在方法区,值在堆
- Java语言只有值传递,子方法中的引用存在栈中,对象存在堆中
- 常量池存放在堆中
- JDK1.7之前常量池是存放在永久代(hotspot虚拟机对方发区的实现)中 ,方法区与堆是独立的
- JDK1.7字符串常量池从永久代中移到了堆内存中,属于堆内存的一部分。
- JDK1.8移除了永久代并由元空间(metaspace)代替,存放在本地内存(native space)中。并没有对常量池再做变动。即常量池一直在堆中
- 为什么用元空间替换永久代
- 元空间在直接内存,最大限度避免oom
- 在方法中声明的基本数据类型局部变量存储在栈上,在类中声明的基本数据类型存储在堆上
JVM指针压缩
- 使用压缩指针可以在64位系统中利用32位的对象引用获得超过4G的内存寻址空间。
- Java对象存储存在对齐补充(对象占用的空间必须是8的倍数),后三位都为000,所以将000去掉存储,寻址时通过左移三位恢复
- JVM虽然额外的执行了一些位运算但是极大的提高了寻址空间,并且将对象引用占用内存大小降低了一半,节省了大量空间。况且这些位运算对于CPU来说是非常容易且轻量的操作