在JVM(一)中简单的描述了JVM的加载过程和JVM的内存区域区分。这篇主要对于垃圾回收机制、垃圾回收算法、垃圾回收器等进行简单的说明
一、JVM是怎么对对象进行回收的?
JVM中使用垃圾回收机制来确保对无用对象等的回收,说到垃圾回收机制,需要先了解堆的区域划分和分布
一、堆的分布
在jvm堆内存分布中,主要分代有年轻代、老年代(永久代一般指方法区)
在创建对象时一般会创建两种对象:
1)、存活时间短:一般时类中的变量对象.
2)、存活时间长:一般是创建静态变量/大对象/多次gc不被回收的对象(线程共享)
为了针对这个现象,JVM的堆内存采用了分代的模型,存活时间短的对象一般在年轻代,经过多次小gc的一般放在老年代。原因如下:
(1)默认区域大小比例1:2
因为年轻代的对象数目多、且存活时间短,所以需要经常去回收这个区域的无用对象。所以在对年轻代和老年代进行划分的时候是1:4进行划分的,这样年轻代因为内存比较小就会经常触发MinorGC,从而达到经常对年轻代进行回收对象的效果。
而老年代是存放那些在年轻代gc多次还没有被回收的对象,这些对象的存活时间长,如果经常回收这些数据每次只能回收少量对象,这样效率就会低下,所以将老年代的内存分多些就可以多放一些对象,这样相当于减少了FullGC的次数了
(2)使用不同算法进行回收
年轻代要经常进行回收,而老年代需要回收的比较少,所以对不同的年代采用不同的回收算法。(当然也有年轻代和老年代都shi'y)
上面对于堆的年代分类进行简单说明,至于各个年代使用的是什么算法,具体的信息下面说明
永久代:永久代不属于堆内存,一般指的是方法区(存放类信息、静态常量,常量池)。那方法区什么时候进行垃圾回收?(JVM垃圾回收也针对方法区)
——首先该类的所有实例对象都已经从Java堆内存里被回收,其次加载这个类的ClassLoader已经被回收,最后,对该类的Class对象没有任何引用(1、对应类加载器被回收 2、对应的实例对象在堆中被回收 3、class对象没有被引用)
二、对象怎么从年轻代到老年代的?
一般的对象放置都是先放进新生代,然后经过15MinorGC后还未被回收的对象会被放进老年代,只有少部分特殊的对象(特别大的超大对象)会不经过年轻代直接进入老年代中
下面是堆中对于年轻代和老年代的划分:
新生区
分为两部分: 伊甸区(Eden space)和幸存者区(Survivor pace) ,所有的类都是在伊甸区被new出来的。幸存区有两个: 0区(Survivor 0 space)和1区(Survivor 1 space)。当伊甸园的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC),将伊甸园区中的不再被其他对象所引用的对象进行销毁。然后将伊甸园中的剩余对象移动到幸存 0区。若幸存 0区也满了,再对该区进行垃圾回收,然后移动到1区。此后eden区来的对象存到1区,当1区满后则进行gc然后将对象放到0区,依次循环到达某个次数时则会将仍然存活的对象移动到老年区。(复制算法)
老年区
新生区经过多次GC仍然存活的对象移动到老年区。若老年区也满了,那么这个时候将产生MajorGC(FullGC),进行老年区的内存清理。若老年区执行了Full GC之后发现依然无法进行对象的保存,就会产生OOM异常“OutOfMemoryError”
讲到这里,先不急着讲年轻代、老年代的gc过程,回收算法、垃圾回收器等知识,我们先来上手实践一下怎么配置JVM参数。看看怎么给整个堆、方法区、栈、堆中各个年代的内存大小进行配置。
三、配置JVM参数
在JVM内存分配中,有几个参数是比较核心的,如下所示。
-Xms:Java堆内存的大小
-Xmx:Java堆内存的最大大小
-Xmn:Java堆内存中的新生代大小,扣除新生代剩下的就是老年代的内存大小了
-XX:PermSize:永久代大小
-XX:MaxPermSize:永久代最大大小
-Xss:每个线程的栈内存大小
这些参数的设置对应下面JVM内存大小分布
1、-Xms和-Xmx,分别用于设置Java堆内存的刚开始的大小,以及允许扩张到的最大大小。对于这对参数,通常来说,都会设置为完全一样的大小。
2、-Xmn,这个参数也是很常见的,他用来设置Java堆内存中的新生代的大小,然后扣除新生代大小之后的剩余内存就是给老年代的内存大小。
3、-XX:PermSize和-XX:MaxPermSize,分别限定了永久代大小和永久代的最大大小,通常这两个数值也是设置为一样的。如果是JDK 1.8以后的版本,那么这俩参数被替换为了-XX:MetaspaceSize和-XX:MaxMetaspaceSize
4、-Xss,这个参数限定了每个线程的栈内存大小
知道了JVM参数的大概意思,那么现实中我们怎么配置JVM的启动参数?
1、开发阶段:idea中
然后应用启动即可。
2、部署阶段
可以使用java -Xms512M -Xmx512M -Xmn256M -Xss1M -XX:PermSize=128M -XX:MaxPermSize=128M -jar App.jar 进行部署。
(自己看了下公司的微服务部署:java -Xmx1g -jar ***.jar java -Xmx512m -jar ***.jar)
获取JVM默认的参数设置
然后启动JVM,就会打印相应的参数信息
四、怎么大概的去预估堆内存大小?
aa