1:JVM概述
- JDK:Java开发环境
- JRE:Java运行环境
- JVM:JDK的bin目录下的Java.exe文件,启动时就会创建一个Java虚拟机,可以模拟CPU执行指令的程序
JVM执行流程:
- Java源程序通过javac编译为.class的字节码文件
- 将.class文件放入类加载子系统
- 经过类加载子系统后上JVM运行
- 可以通过本地方法接口调用本地方法库
JVM运行时数据区域:
- 堆(线程共享)
- 方法区(线程共享)
- Java虚拟机栈(线程私有)
- 本地方法栈(线程私有)
- 程序计数器(线程私有)
2:堆
堆:
线程共享的区域,保存程序创建的对象(是对象,而不是变量)
同过JVM运行参数可以设置堆的最大内存和最小内存:
-Xms10m最小堆内存 -Xmx20m最大堆内存
java -Xms10m -Xmx20m Main
在进行GC时,会将堆划分为老年代和新生代两个区域,而新生代区域又会被划分为三块8:1:1的区域,分别为伊甸区(Eden),两个幸存区(Survivor)
3:方法区
方法区:
线程共享,用来存放被虚拟机加载的类信息(.class的字节码文件进行类加载),比如常量,静态变量等,即是编译后的代码数据,且堆中会生成一个类对象
类加载的过程:
- 加载: 加载class文件到Java进程的内存
- 验证: 验证class文件格式等是否符合Java虚拟机规范
- 准备: 为静态常量赋初始值,为静态变量赋默认值
- 解析: 将常量池中的符号引用替换为直接引用
- 初始化:Java虚拟机真正执行Java代码,构造类对象,执行态代码块,为静态变量赋值
4:Java虚拟机栈
Java虚拟机栈:
生命周期和线程相同,属于线程私有,每一个方法执行时都会创建一个栈帧进栈,结束后出栈
栈帧:
方法执行时创建
- 局部变量表:放入编译时可知的基本数据类型,以及对象的引用
- 操作栈:每一个方法的栈帧都会进行入栈和出栈的操作
- 动态链接:指向运行时常量池的方法引用
- 方法返回地址:下一行该执行的代码的地址
5:本地方法栈
本地方法栈:
和Java虚拟机栈类似,只不过是为本地方法使用的栈,即调用一些Native方法则会使用本地方法栈保存栈帧
6:程序计数器
程序计数器:
用来记录当前代码执行的行号
7:OOM
除了程序计数器外,其它的运行时区域都可能会产生OOM,即内存溢出
内存溢出:
存放的数据大小超过该区域的内存大小
内存泄漏:
由于线程生命周期过长导致一些不会被引用的数据未被GC回收,导致可用空间越来越小,可能会导致内存溢出
解决内存溢出:
- 重启程序
- 修改代码
8:StackOverFlow
StackOverflow:
虚拟机栈和本地方法栈溢出,由于入栈的栈帧数量过多,栈的深度超过JVM规定的最大深度,导致此错误,可能原因是不合理的递归