目录
案列
public class JVM {
public static void main(String[] args) {
int i = 8;
i = i++;
System.out.println(i);
}
}
请问最后答案是多少?
答案是8。
为什么呢?你看了这篇文章就了解个大概了。
runtime Data Area(运行时数据区)
运行时数据区是非常重要的一个执行区。
jvm 运行时的区域一共有这么几个区域
- JVM stacks jvm栈 每个线程对应一个栈
- Frame 栈帧 重点 每个方法对应一个栈帧
- Local Variable table 本地局部变量表
- Frame 栈帧 重点 每个方法对应一个栈帧
注意:非static方法的LocalVariableTable里会有this
ps:这个是上一篇说到的Jclasslib idea的插件(方便开发者读取并分析内存的帮手)
Instructions(指令集)
- Operand Stack 栈
0 bipush 8
2 istore_1
3 iload_1
4 iinc 1 by 1
7 istore_1
8 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
11 iload_1
12 invokevirtual #3 <java/io/PrintStream.println : (I)V>
15 return
jvm会把class 方法解析成一个个字节码指令。每个指令对应的就是jvm的操作。
如果你不知道指令代表什么意思可以ctrl 点进去 会直接有对应的链接进去观看 右键会有一个show jvm spec 会直接跳到对应的地址
分析:
第一步是压栈 把8放在栈里面
第二步是 把int值放在局部变量表 也就是LocalVariableTable里 的1位置
这两步完成的时候也就int i = 8 这个指令完成
第三步是 把局部变量表 1这个位置拿出来 压栈 也就是把i又拿进来了
第四步是 把局部变量表 1这个位置加1 所以 这时候局部变量表的i已经变成9了 但是栈里面是8
第五步是 和第二部一样 又把栈里的8 放在了1位置 也就是i覆盖了9
第六步也就是返回 所以就是8
-
-
- Dynamic linking 动态链接 其实就是指向常量池的符号链接 其实就是A方法里 一个B方法 的链接 链接就是从常量池找
- return address 返回地址 方法a调用方法b 如果有返回值,b方法的返回值放在什么地方
-
以上就是每个栈里面的东西
- Program Counter 简称pc 指的是下一条指令位置 实际上特别小 每个线程都有自己的pc
虚拟机的运行,类似于一个循环
while(not end){
取pc的位置,找到对应位置的指令
执行该指令
PC++
}
- Direct Memory 直接内存nio jdk1.4以后的内容 也就是可以直接访问操作系统内存的
不归jvm管 归os管 省了拷贝过程比io 0拷贝
- native method stacks 栈 本地方法 调用c c++ jni 一般不用去管
- method area 方法区 装的是各种class 各种常量池的内容 所有线程共享 (重点)
- Perm Space(<jdk1.8)永久区
字符串常量位于PermSpace
FGC不回收 bug
大小启动的时候指定,不能变
-
- Meta Space(>=1.8) 元数据区
会触发FGC清理
字符串常量位于堆
不设定的话,最大就是物理内存
方式区是逻辑上的概念 具体的实现是Perm Space 和Meta Space是具体的实现
思考 如何证明1.7 位于perm 而1.8位于heap?
结合GC 一直创建字符串常量,观察堆和metaspace
- Heap 堆 GC 重点中的重点 所有线程共享
- run-time constant pool 常量池
注意:这里就是sipush 200 和之前讲的bipush 8 有点不一样 所以大家一定要自己ctrl点进去自己看 sipush 是因为已经超过了127 一个字节的大小(-128到127),所以才会默认转成short类型,还有其他类似于ldc,ldc2_w 也是。ldc是从常量池里拿数据压栈,所以这里是想说可以多去看看指令集的解释,比直接模仿印象更深刻,懂得也就更多。
补充:
基于栈的指令集 是jvm的 指令集
基于寄存器的指令集是os的指令集
hotspot 的local variable table 类似于寄存器
常用指令
store
load
pop
mul
sub
invoke
- InvokeStatic
- 调用静态的方法
InvokeVirtual
-
- 多数的情况 new 一个东西 非静态的
- InvokeInterface
- 子类赋到父类的一个实现 List list = new ArrayList();
- InovkeSpecial
- 可以直接定位,不需要多态的方法,构造方法 和 private 网传final 方法不是的
- InvokeDynamic
- jvm最难的指令
- 动态语言 lambda 表达式或者反射或者其他动态语言scala kotlin,或者CGLib ASM,动态产生的指令