文章目录
一、Java虚拟机是什么
Java虚拟机是指啥?
通过“java 类名”启动一个java进程
- 运行java.exe(启动:加载java.exe文件的内容到内存,执行其中的指令)这个静态的可执行文件(程序)——全局path路径中,找是否有一个java.exe的文件,找到就运行
- 系统为进程分配了一块内存空间,执行进程的代码指令:其中就会创建java虚拟机,把“java 类名”对应的class文件,加载到进程的方法区(内存):类加载
类加载做了哪些事情
(1)代码,方法等等放在方法区
(2)堆里边,生成了一个类对象
运行代码: 就是类.main方法的一个调用(由java虚拟机来调用)
java虚拟机中,启动了一个线程,来执行main方法:执行的方式,是java虚拟机把class字节码的内容,翻译为所在系统的机器码
简单说:启动一个java进程
会创建并启动一个java虚拟机
并加载class字节码,运行时翻译为机器码,让cpu去执行
HotSpot VM名称中的HotSpot指的就是他的热点代码探测技术。它能通过计数器找到最具编译价值的代码,触发即时编译(JIT) 或线上替换;通过编译器与解释器协同工作,在最优化的程序响应时间与最佳执行性能中取得平衡
JIT:完整名称:JIT即时编译器
所谓热点代码,比如while循环,会执行很多次:如果每次边运行边翻译,效率就很低
JIT的工作,就是运行时,将热点代码直接编译成机器码,下次就不需要翻译,就可以直接执行,效率高
JVM产品:
官方产品:HotSpot
还有很多产品:
只要遵循java虚拟机规范的,就是java虚拟机
二、JVM运行流程
三、JVM运行时数据区
1.堆(线程共享)
堆里边还有一块区域叫做“字符串常量池”
创建的对象都保存在堆中
2.Java虚拟机栈(线程私有)
关于局部变量表,结合代码理解:
结合代码,理解栈和栈桢:
3.本地方法栈(线程私有)
本地方法栈: Java虚拟机可能调用系统函数(本地方法),Java程序中也可能调用native方法(本地方法)
这些本地方法,是系统提供的方法入口,调用执行时也需要一定的内存空间
4.程序计数器(线程私有)
程序计数器: 行号指示器(线程执行到某行代码,需要记录行号)
5.方法区(线程共享)
用来存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
JDK1.7时,方法区是在Java进程的内存中
JDK1.8时,称为元空间,属于本地内存(不在Java进程内存)
运行时常量池,保存:
- 字面量:String,常量(final修饰),基础数据类型的值
- 符号引用:类和结构的信息,字段和方法包括其描述信息
6.内存布局中的异常问题
OutofMemoryError: 如果新创建的数据,保存到对应的内存区域,如果空间不足,就出现OOM(内存溢出)
StackOverFlowError: 方法调用太深,就抛这个错;某个线程调用方法时,方法又调用方法(线程栈中,方法栈桢入栈,数量太多)
比较常见:递归方法调用
观察堆OOM:
public class 堆OOM {
static class OOMObject {
}
public static void main(String[] args) {
List<OOMObject> list =
new ArrayList<>();
while(true) {
list.add(new OOMObject());
}
}
}
图片解释:
出现内存泄露如何解决?
1.从程序本身入手解决:
(1)定时清理不用的数据(定时器)
(2)使用弱引用、软引用来保存数据(这里还不太了解,是Java中的对象引用类型)
(3)这种方式,可能会比较困难,特别是比较大,又比较老的项目
2.加大内存(不用的数据还存在,但加大内存,就还能保存,就不会出现OOM)
3.定时重启程序(相对来说,代价比较小,也很有效;很多网站在凌晨就会重启)