jvm的主要组成有:类加载器,运行时数据区,程序计数器,堆,jvm栈,本地方法栈,方法区,执行引擎。
在jvm装载时会将编译好的字节码文件通过类加载器加载进入程序的方法区(调用直接内存),其中包括运行时常量池(常量,静态变量),以及一些类的相关属性,比如方法的字节码。
jvm栈
:线程私有,每次调用方法都会压入一个栈帧,方法执行完成,栈帧立马释放,所以后执行的子方法先弹出,栈帧包括局部变量表,操作数栈,动态链接,程序出口。
假如初始化一个int a = 0; 会将0先存入操作数栈,之后在局部变量表中开辟空间,之后将操作数栈的数据赋值给局部变量表。 假如要计算 int c = a + b。 这时候会将局部变量表中的 a,b数据压入操作数栈,通过执行引擎执行a+b。 之后会在局部变量表开辟c的空间,将a+b的结果从操作数栈赋值到局部变量表。
动态链接存放的就是上面提到的方法区中类方法的字节码的指针,称为动态链接的原因是只有在类加载器执行完成之后,通常我们new出来的对象都有一个对象头,而这个对象头里面包含了方法区中方法字节码的指针,动态链接通过这个对象头才能动态找到指针,所以称之为动态链接。
每个栈都有他自己的程序计数器,记录执行到哪一行代码,下面该执行哪一行代码,这个计数器由执行引擎来更新。
程序出口也类似于程序计数器,不过他记录的是子方法执行完之后,父方法应该接着执行哪一行。
堆内存包括伊甸园区,survivor区(分为from区域和to区域),老年代区
伊甸园区填满之后会触发minor gc,这个时候对象年龄就会+1,年龄记录在对象头中,之后会将这些对象放入到from区域,假设经过一段时间from区域也满了,就会再次触发minor gc,将from区域所有剩余对象年龄+1且全量复制到to区域,这时from区域就空出来了,之后伊甸园满了重新触发gc,再将没有被回收的对象放入到from。
每次触发gc年龄+1,且伊甸园没有被gc的对象会全量复制到survivor区中空闲的那一个区。
假如年龄增长到15会直接挪到老年代(如:静态变量存放的对象,连接池等,守护线程)
如果老年代满了就会触发full gc
jvm调优主要调full gc的次数以及每次执行时间。