虚拟机底层结构:
从上往下分为 四层部分:
【1】类加载器 ClassLoader
.class 的字节码文件会通过类加载器 ( ClassLoader )加载到 Java虚拟机当中。
【2】JVM 内存结构 (包括有 方法区、堆、虚拟机栈、程序计数器、本地方法栈)
【3】执行引擎 (包括有 解释器、即时编译器、垃圾回收)
解释器: 方法执行时,每行代码是交给 执行引擎的解释器 进行执行
即时编译器: 方法当中的热点代码(被频繁调用的,被频繁使用的)相关代码 会交给 即时编译器 进行执行。 相当于是对代码优化后执行。
垃圾回收: 会对堆里面,不再引用的代码,进行回收处理。
【4】本地方法接口(被调用时使用本地方法栈)
存在一些底层与操作系统进行交互的代码,主要存在于本地方法接口当中。 通过本地方法接口,调用操作系统相关的方法。
Java的内存划分为5部分
1.虚拟机栈(Stack):存放的都是方法的局部变量,方法运行时一定是在栈中运行
局部变量:方法的参数,或者是方法{}内部的变量
作用域:一旦超出作用域,立即从栈中消失
2.堆(Heap):凡是new出来的东西都在堆内存中
堆内存里面的东西都有一个地址值:16进制
堆里面的数据都有默认值,规则:
如果是整数:默认值为0
如果是浮点数:默认值为0.0
如果是字符:默认值为‘u0000’(空字符)
如果是布尔:默认值为false
如果是引用类型:默认值为null
特点:
1.堆内存,被线程共享。 需要考虑线程安全问题
2.堆内存,存在地址值 和 默认值
3.堆内存,有垃圾回收机制,当 GC 空闲时进行堆内存垃圾回收
3.方法区(Method Area):存储.class相关信息,包含方法的信息
方法区在逻辑上是堆的组成部分,是规范,不同的虚拟机实现是不相同的,JVM规范当中,并不做强制要求
我们常用的虚拟机在jdk1.8以前是采用永久代实现的(堆内存一部分),1.8后采用元空间实现(本地内存、直接内存)
方法区在虚拟机启动的时候,被创建
方法区存储类结构相关的信息(成员变量、方法数据、成员方法、构造方法)、运行时常量池
其中运行时常量池中的 StringTable(串池) 在jdk1.8以前和其他常量一样属于方法区(永久代);1.8后独立出来属于堆(因为StringTable频繁创建销毁,在堆中垃圾回收效率高,不可一起归为元空间),其他常量属于方法区(元空间)
运行时常量池:
方法区是线程共享的, 需要考虑线程安全问题
4.本地方法栈(Native Method Stack):专门用于加载 native 修饰的本地方法,主要是与计算机底层硬件进行交互使用
5.程序计数器(pc Register):与CPU相关,字节码指令执行过程当中,记录下一条指令的执行地址,线程私有,不会存在内存溢出
栈内存的设置:
并不是说栈内存设置越大越好,栈内存设置越大,每个线程调用的方法可以更多,也就是栈帧可以更多,但是相应能创建的线程就会减少,因为物理内存是固定的。栈内存采用默认值即可。
堆内存诊断:在测试时可以把堆内存设置小一些,提前暴露出程序存在的问题
JVM常见问题解决:https://www.cnblogs.com/roadlandscape/p/12042137.html