1、JVM内存模型
a、栈:
包括虚拟机栈和本地方法栈。
虚拟机栈为线程私有,生命周期与线程相同。java方法执行时会创建一个栈帧,里面保存着对象引用、基本类型数据等
本地方法栈和虚拟机栈类似,虚拟机为java方法服务,为本地方法栈为Native方法服务。
b、方法区:
方法区其中一种实现为永久代(PermGen),他是所有线程共享的区域,里面保存着类信息、静态变量、常量等。
c、堆(heap):
所有线程共享区域,里面保存着对象和数组(java8开始静态变量和常量也保存在堆中)
d、PC寄存器(程序计数器):
线程私有,记录着每个线程运行的位置
e、元空间(Metaspace):
从java1.7开始,永久代里的数据有一部分数据开始移到堆中保存了,到了java1.8,永久代已经完全移除,取而代之的是元空间。他的作用类似永久代
2、个别内存区域的单独介绍
a、堆:
堆内存分为新生代(伊甸园eden、幸存区from Survivor -to Survivor ,默认大小8:1:1(对象的生命周期不一样,98%的对象在minor gc时被回收掉,这样可以利用90%空间,这个大小是经验值))和老年代。堆数据优先保存在eden区,大对象直接进去老年区。当jvm经历了Minor Gc时,对象从eden区移至Survivor区。当对象在Survivor经历了MaxTenuringThrehold(默认15)-1(从Eden到Survivor已经经历了1次)次后仍然存活,对象移至老年代。
b、元空间:
java8开始,jvm不在支持PermSize和MaxPermSize参数配置永久代。但是可以通过 -XX:MetaspaceSize和 -XX:MaxMetaspaceSize(可防止元空间占用太多本地内存)来配置元空间大小。
元空间与永久代最大的区别是:元空间不在虚拟机中,而在本地内存中。同时原来的常量移到了堆中的运行时常量池,静态变量也移到堆中了,因此java8中的堆内存会比以前大很多
由于永久代每次FullGc都会使永久代数据移动,同时类信息的大小比较难以确定等原因,使得永久代大小也难以确定。因此永久难以调优。元空间有元空间虚拟机管理,同时可以动态管理元空间大小。节约了GC扫描和压缩时间。
3、对象已死:
a、引用计数法:给对象引用加一个计数器,当一个地方引用它一次,加1,引用失效时,减1,为0时则对象已死。
缺点:当实例相互引用时,无法判断是否为已死
b、可达性分析(根搜索算法):GcRoots不可达时,已死。(通过一系列名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时)
哪些可以作为GC ROOT(在运行中的变量):虚拟机栈本地变量表引用的对象,类静态变量引用的对象,常量引用的对象,本地方法栈中JNI引用的对象
4、垃圾回收算法
a、标记-清除:
缺点:标记和清除的效率都不高,以及标记清除后会产生大量的内存不连续的碎片
b、复制算法:
介绍:把内存分为俩快,一个内存满时,将活的对象移动的另一个内存,将满的内存清空
缺点:浪费空间
ps:eden -> survivor使用的就是复制算法,当eden区存活率高时,使用老年代空间(伊甸园和幸存区默认空间比例8:1)
fromSurvivor -> toSurvivor也使用的是复制算法
c、标记-整理算法:
与标记-清除算法一样,但是这个是标记后让所有存活的对象移到一端,然后清空另一端
d、分代收集算法:
根据不同的区使用不同的回收机制
ps:一般分为新生代和老年代,新手代存活率低使用复制算法,老年代存活率高使用标记清除或者标记整理算法。
minor gc之前,进行担保空间等检查,不满足条件,直接full GC(major gc 对于老年代)
5、FullGc的条件
a、System.gc()方法调用
b、老年代空间(old/Tenured)不足
c、永生代(元空间)空间不足
d、CMS GC时出现promotion failed和concurrent mode failure
e、统一Minor Gc晋升到老年代的平均值大于老年代的剩余空间
f、堆中分配很大的对象,老年代中没有足够的连续空间保存该大对象
6、垃圾回收器
垃圾回收有很多类型,这个主要回顾一下CMS和G1
a、CMS:
优点:减少程序的停顿时间(但是在初始标记和重新标记时依然会发生 stop the world)(Parallel Scavenge优点关注吞吐量)
缺点:由于在gc时,程序仍然在运行,这导致垃圾回收并不一定完全,甚至可能发生错误导致执行fullGC,同时这也导致cms的回收频率比较高,影响应用程序的吞吐量(要求CPU),由于cms采用标记清楚算法,易产生大量空间碎片,这导致给大对象分配空间时可能无法找到连续空间,从而导致fullGC
b、G1
g1回收器将堆空间划分为多个区域(即会有个多个Eden、多个Survivor、多个old区、多个Humongous区(用于保存大对象的区域))
g1回收器或在第一时间处理垃圾最多的区域,虽然也会暂停应用,但是会花费较少的时间回收垃圾最多的区域。
g1与CMS相比的优点:1、因为划分为多个区域,回收时减少了内存碎片的产生。2、g1适用与新生代和老年代,CMS只适用用老年代。