JVM内存模型包含:堆、栈、方法区、程序计算器、本地方法区。
堆:
堆是存放的是在程序运行中new出来的对象,里面包含了4个区,伊甸区、from、to、老年代。
- 首先new出来的对象先进伊甸区
- 然后当伊甸区满的时候,会触发gc,然后伊甸区存活下来的会进入from,这个时候伊甸区和to是空的
- 当第二批伊甸区满的时候,在次触发gc(这里gc包含from也会gc),然后会与from一起迁移到to,这个时候from是空的,伊甸区也是空的
- 第三批伊甸区满的时候,触发gc(这里gc包含to也会gc),然后伊甸区与to一起迁移到from
一直来加15次(默认,可设置),这时还存活的对象并会放入老年代。
如果老年代满的时候,系统会触发full gc,这个gc会很耗性能。可能会出现STW现象,机率还挺高的。
栈:
栈存放着一组栈帧,栈帧可以理解为所对应的方法进出栈的过程,栈帧里面包含了:局部变量表、操作数栈、动态链接、方法出口
局部变量表:存放栈帧里所产生的对象值
操作数栈:存放在执行过程中计算产生的值
动态链接:是指在执行过程中,需要用到局部变量表里引用对象,并且执行这个对象的代码的时候,而这个对象是通过指向所对应的类元信息获取怎样执行,这个动态指向理解为动态链接。
方法出口:指在执行过程中,引用了对象的并执行这个对象的方法并返回的时候,程序计算器所指向的下一个地址,简单的说其实就是保存现场。
例:
这个是java代码,我们通过这个java文件生成一个反汇编文件,可通过javap生成
现在我们看这上文件,是不是跟我们的java文件结构挺类似的。
这个是我们java的构造方法:
aload_0:代表把局部变量的第1个变量加载到操作数栈顶。这个第一个变量代码this。
invokespecial:代表着调用超类构造方法,这里#1所代表的是在当前类常量池中的1号元素,这个1号元素是什么呢,就是这个Method java/lang/Object."<init>":()V,返回为void的object.init方法,这里执行需要2字节的操作数,所以这里的1->4跳过了2个字节
然后返回
然后我们看第二个方法,这个是我们所说的main方法:
getstatic:获取当前类常量池中的2号元素的静态域,并将其值压入栈顶,这里所指的是Field java/lang/System.out:Ljava/io/PrintStream; PrintStream的out字段。这里面L代表的是类实例
ldc:将3号元素从常量池中推送到栈顶。这个元素就是
invokevirtual:调用4号元素所指向的实例方法
invokestatic:调用5号元素所指向的静态方法,并压入栈顶
fstore_1:将栈顶的元素,存放到第2个局部变量(第一个局部变量是this)
getstatic:同上
ldc:同上,但是它指向的元素是
iconst_1:将int型的1推送到栈顶
anewarray:创建一个元素7的类,并将其引用值压入栈顶
dup:复制栈顶数值并将复制值压入栈顶
iconst_0:将int型的0推送到栈顶
fload_1:将局部变量表中的第2个值加载到栈顶
invokestatic:调用8号元素的静态方法,这个静态方法是Float.valueOf:F
aastore:将栈顶引用型数值存入指定数组的指定索引位置
invokevirtual:调用9号元素的实例方法,这个方法是printf:PrintStream
pop:栈顶数值出栈 (该栈顶数值不能是long或double型)
return
然后我们看5号元素所指向的静态方法
iconst_1:将int类型1推送到栈顶
istore_0 :将栈顶int型数值存入第一个局部变量
getstatic:获取当前类常量池中的2号元素的静态域,并将其值压入栈顶,这里所指的是Field java/lang/System.out:Ljava/io/PrintStream; PrintStream的out字段。这里面L代表的是类实例
ldc:同上,只是这个元素是10,指的是
iconst_1:将int类型1推送到栈顶
anewarray:创建一个元素7的类,并将其引用值压入栈顶
dup:复制栈顶数值并将复制值压入栈顶
iconst_0:将int类型0推送到栈顶
iload_0:将int类型的第一个全局变量推送到栈顶
invokestatic:调用11号元素的静态方法。这里指的是Integer.valueOf:I
aastore:将栈顶引用型数值存入指定数组的指定索引位置(应该说的是把float.valueOf后的值放到栈顶)
invokevirtual:调用9号元素的实例方法。这里指的是printf:PrintStream
pop:栈顶数值出栈 (该栈顶数值不能是long或double型)
iconst_2:将int类型2推送到栈顶
istore_1:将栈顶int型数值存入第二个局部变量
getstatic:获取当前类常量池中的2号元素的静态域,并将其值压入栈顶,这里所指的是Field java/lang/System.out:Ljava/io/PrintStream; PrintStream的out字段。这里面L代表的是类实例
ldc:同上,只是这个元素是10,指的是
iconst_1:将int类型1推送到栈顶
anewarray:创建一个元素7的类,并将其引用值压入栈顶
dup:复制栈顶数值并将复制值压入栈顶
iconst_0:将int类型0推送到栈顶
iload_1:将int类型的第二个全局变量推送到栈顶
invokestatic:调用11号元素的静态方法。这里指的是Integer.valueOf:I
aastore:将栈顶引用型数值存入指定数组的指定索引位置
invokevirtual:调用9号元素的实例方法。这里指的是printf:PrintStream
pop:栈顶数值出栈 (该栈顶数值不能是long或double型)
iload_0:将第一个全局变量加载到栈顶
iload_1:将第一个全局变量加载到栈顶
iadd:将栈顶2个int型数值相加,并把结果存放到栈顶
i2f:将栈顶的int型强转成float,并把结果存放到栈顶
fconst_2:将float型2推送到栈顶
fdiv:将栈顶的2个float数相除,并把结果存放到栈顶
fstore_2:把栈顶的float存放到第三个全局变量中
fload_2:加载float型第三个的全局变量的值到栈顶
freturn:返回栈顶的float值
这3个方法的全局变量表和操作数栈大致这样的:
方法区(元空间):
这个主要存放静态变量、常量、类元数据信息等。
程序计算器:
这个指的是程序运行中,所指向的下一个地址。
反编译文件前面的数字是所说的地址
本地方法区:
这个指的是存放native的方法区
像这类的方法
一些jvm的指令集可查看:
- https://www.jianshu.com/p/bc91c6b46d7b
- https://blog.csdn.net/zhangpan19910604/article/details/52254053
昨天刚看了一些资料,欢迎吐槽~~~~~~!