4:JVM内存模型深度剖析与优化(结构体系 与 线程私有内存)
2021-04-10 本文已影响0人
_River_
1:Java是如何实现跨平台的
1:Java源代码
2:经过JDK中Javac 编译
3:字节码文件(.class)
4:JVM 类加载器 进行加载字节码文件
5:方法:解释:
1:解释器 逐行解释执行
2:机器可执行的二进制机器码
5:方法:编译:
后续引进:JIT即时编译器(Just In Time Compiler)
处理热点代码(一次编译 多次执行)
2:JIT 运行时进行编译
3:机器可执行的二进制机器码
4:编译完成后机器码保留
5:机器码下次可以直接使用

2:JVM整体结构及内存模型
简略流程图:
步骤1:类装置子系统:JVM 类加载机制对 java.Math.class (字节码文件进行类加载)
步骤2:运行时数据区(内存模型)进行处理(以后调优主要是处理这里)
步骤3:字节码执行引擎:进行执行

public class Math {
public static final int initData = 666;
public static User user = new User();
//一个方法对应一块栈帧内存区域
public int compute() {
int a = 1;
int b = 2;
int c = (a + b) * 10;
return c;
}
//一个方法对应一块栈帧内存区域
public static void main(String[] args) {
Math math = new Math();
math.compute();
}
}
注意:栈(线程) 程序计数器 堆 方法区 本地方法栈
实际上都是一块块内存区

3: 尝试对字节码文件进行分析:
javap -v Math.class (在控制台反编译 有更多附带信息)
javap -v Math.class > Math.txt(反编译后生成文件 有更多附带信息)
javap -c Math.class (在控制台反编译)
javap -c Math.class > Math.txt (反编译后生成文件)
执行完命令后 javap -c Math.class > Math.txt 后查看Math.txt文件
请直接跳转到 5:JVM内存模型深度剖析与优化(JVM指令手册)(结合文件讲解)


4:栈(线程) 详解运行时数据区(内存模型):
栈(线程)=线程栈 = 虚拟机栈 线程私有 作用:存放局部变量的

比如(红色箭头):主线程(main线程) 运行,在栈(线程)这一块内存区域 里面会分配 一小块内存区域 给 主线程
比如(红色箭头):一条线程(其他线程) 运行,在栈(线程)这一块内存区域 里面会分配 一小块内存区域 给 这一条线程
那在main线程里面又有什么东西:
1:main线程里面有 main()方法 一个栈帧(黄色箭头)
2:main线程里面有 compute()方法 一个栈帧(黄色箭头)
栈:里面的栈帧 先进后出
compute() 方法出口 返回 (后执行 先执行完)
main() (先执行 后执行完)
在栈帧里面有
1:局部变量表:(里面有多块 局部变量 1 2 3):存放 一个个局部变量
2:操作数栈:(里面是一整块 压栈) :临时存放操作数 的 栈内存空间
简单关系:
0: iconst_1 //将int类型常量1压入操作数栈
1: istore_1 //将int类型值存入局部变量1 操作数栈中int类型常量1出栈
2: iconst_2 //将int类型常量2压入操作数栈
3: istore_2 // 将int类型值存入局部变量2 操作数栈中int类型常量2出栈
4: iload_1 //从局部变量1中装载int类型值 回到 操作数栈
5: iload_2 //从局部变量2中装载int类型值 回到 操作数栈
注意(蓝色箭头):执行顺序与程序计数器有关 查看下面
3:动态链接:在程序运行的时候 符号引用变为直接引用 (代码所存在的方法区的位置)(需要理解好几遍)(后面还会讲)
4:方法出口:返回到线程的某个地方继续去执行
特别注意(绿色箭头):
main()栈帧里面的局部变量表里面的 math存放的是 在堆里面math的内存地址
所以:如果在栈帧里面的局部变量表有对象 ,那么实际上存放的都是 该对象的内存地址。
5:程序计数器 详解运行时数据区(内存模型):
程序计数器 线程私有 作用:存执行顺序
比如:主线程(main线程) 运行,在程序计数器 这一块内存区域 里面会分配 一小块内存区域 给 主线程
比如:一条线程(其他线程) 运行,在程序计数器 这一块内存区域 里面会分配 一小块内存区域 给 这一条线程
程序计数器(线程私有) 存放该线程正在执行或者马上将要执行代码的行号
字节码执行引擎:
执行Math.class里面的线程 会修改程序计数器的计数值,用于记录该线程的代码执行到哪里了
比如说:
该线程的时间片以及使用完了,资源要被回收给其他优先级更高的线程使用,
那么这个时候 程序计数器 就需要 记录该线程执行到代码的行号,方便之后再次获取资源的时候恢复。

6:本地方法 详解运行时数据区(内存模型):
本地方法 线程私有 作用:调用其他语言
关键字:native
如:private native void start()
当Java面世时,native方法一开始 用于Java语言和C语言进行交互,因此当时有很多native方法;
但后续Java语言和其他语言 跨语句的方式越来越多,已经很少有新写的native方法了