jvm负责把class文件翻译为对应操作系统的机器码并执行。
jvm分为执行引擎、类加载器、临时数据区(堆,方法区(元空间),虚拟机栈,本地方法栈,程序计数器)。
1.堆
年轻代:Eden,Survivor(s1和s2)。
老年代。
刚new出来的对象放Eden,满了后触发minor gc。存活的对象放入第一个Survivor。
根据可达性算法,没有被gc roots根(比如:线程栈的本地变量、静态变量、本地方法栈的变量)链条引用的对象都会被标记回收。
当Eden再次满了就再次触发minor gc,针对年轻代的Eden,Survivor回收,存活的对象复制到第二个Survivor,然后直接清空Eden和第一个Survivor。
当下次Eden满了就再次触发minor gc,存活对象复制到第一个Survivor,如此反复。每经行一次minor gc,Survivor里对象年龄+1,当年龄达到了15时,就会被移到老年代(或一批计划被移到Survivor的对象大小超过了Survivor空间的一半,或是大对象都会被直接移动到老年代)。
当老年代满了则会触发full gc。
minor gc和full gc都会STW。
minor gc的时间很短,但full gc时间很长。
jvm调优就是减少STW次数,特别是full gc次数,以及full gc时间。
调优举例:电商大促时,每秒都会产生大量对象(生命周期很短),正常这些对象很快就会被回收,但年轻代配置太小,容易导致每次minor gc时都会有一批对象大小超过minor空间的一半而直接被移到老年代,而这些对象本身不应该被放入老年代,很快老年代被占满导致频繁full gc,影响用户体验。
根据业务场景计算对象大小合理配置各分代大小,减少full gc。
2.方法区(元空间)
常量,静态变量(对象地址),类元信息。
3.虚拟机栈
用来存放方法执行时的数据,线程私有。
栈帧(一个方法对应一个栈帧)
-局部变量表:存一些方法内的变量(非对象)。
-操作数栈:存要用来赋值的涉及到计算的数据。
-动态链接:涉及到其他语言的库。
-方法出口:方法执行完返回父方法的位置。
4.本地方法栈
调用其他语言的方法时存放数据的区域。
5.程序计数器
存放线程执行到方法的具体位置。为了线程被挂起后再次执行时找到执行位置。
网友评论