首页

Java垃圾回收器分类及相关参数配置说明

标签:java,垃圾收集器分类,性能优化,jvm优化,outOfMemory,内存溢出,强引用,软引用,弱引用,虚引用,回收器优化     发布时间:2015-05-27   

一、垃圾回收机原理

Jvm(Java虚拟机)通过专属线程来回收不再使用的内存对象空间,对于处理该任务的进程叫做“垃圾回收器”,根据用户对系统模块的定制或优化需求可以配置不同的垃圾回收器来更有效执行(参考第二章节)。触发垃圾回收器回收场景如下(不在使用的对象)

对象没有引用@b@程序中使用System.exit()@b@发生未捕获异常@b@对象所属的作用域执行完毕@b@程序被意外终止(kill所属进程)

对于对象的引用又分为强引用、软引用、弱引用、虚引用,下面分别举例说明

强引用 - 通常我们创建的对象都是这种形式,对象只有在主动释放引用后才会被释放,形式如下

B b=new B();

软引用 - 采用SoftReference来实现,其内存不足时被回收(用例缓存),形式如下

Object obj = new Object();@b@SoftReference<Object> sf = new SoftReference<Object>(obj);@b@obj = null;@b@sf.get();//有时候会返回null

弱引用 - 采用WeakReference来实现,采用弱引用建立引用的对象没有强引用后,GC时及会被自动释放(第二次垃圾回收时回收,用例 - 监控对象内存状态),形式如下

Object obj=new Object();@b@WeakReference<Object> weakRef=new WeakReference<Object>(object);//可通过weakRef.get来获取对象@b@object=null@b@if(wf.isEnQueued())@b@System.out.print("WeakReference"对象即将被回收);

虚引用 - 采用PhantomReference来实现,每次垃圾回收的时候都会被回收(用例跟踪对象是否从内存中删除)

Object obj = new Object();@b@PhantomReference<Object> pf = new PhantomReference<Object>(obj);@b@obj=null;@b@pf.get();//永远返回null @b@if(pf.isEnQueued())@b@System.out.print("PhantomReference"对象已经删除);

另对象在内存的存活机制 - 当新对象要分配到内存中,首先检查空间是否足够,不够就触发GC进行实时回收,如果对象被长时间引用,改对象逐渐从eden到survivor,最后保存到老年代。下面用java visualVM查看,当新生代满了,对象会转移到老年代,进行加载实例化,如果老年代满了,就抛出outOfMemory异常(详情参见内存优化说明页),如下图1-1所示

Java垃圾回收器分类及相关参数配置说明

图1-1

二、收集器分类&参数配置说明

 JAVA_OPTS="$JAVA_OPTS -server -Xms300M -Xmx790M   -XX:OnOutOfMemoryError=/root/tomcat.sh   -XX:+HeapDumpOnOutOfMemoryError   -XX:HeapDumpPath=/home/app/tomcat7/logs/dump    -XX:ErrorFile=/home/app/tomcat7/logs/error/hs_err_pid.log   -XX:OnError=/root/tomcat.sh   -XX:ParallelGCThreads=4  -XX:PermSize=50M  -XX:MaxPermSize=128M   -XX:-DisableExplicitGC -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled    -Dsolr.solr.home=/home/app/tomcat7/bin/solr-md "

JVM给出了3种选择:串行收集器、并行收集器、并发收集器(如下图所示)。串行收集器只适用于小数据量的情况,所以生产环境的选择主要是并行收集器和并发收集器。

Java垃圾回收器分类及相关参数配置说明

默认情况下JDK5.0以前都是使用串行收集器,如果想使用其他收集器需要在启动时加入相应参数。JDK5.0以后,JVM会根据当前系统配置进行智能判断。

标准参数(-),所有JVM都必须支持这些参数的功能,而且向后兼容;例如:

-client——设置JVM使用Client模式,特点是启动速度比较快,但运行时性能和内存管理效率不高,通常用于客户端应用程序或开发调试;在32位环境下直接运行Java程序默认启用该模式。

set JAVA_OPTS=%JAVA_OPTS% -client -Xms800m -Xmx800m -XX:MaxNewSize=256m

-server——设置JVM使Server模式,特点是启动速度比较慢,但运行时性能和内存管理效率很高,适用于生产环境。在具有64位能力的JDK环境下默认启用该模式,用法示例格式如下:

set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize=256m

非标准参数(-X),默认JVM实现这些参数的功能,但是并不保证所有JVM实现都满足,且不保证向后兼容;

非稳定参数(-XX),此类参数各个JVM实现会有所不同,将来可能会不被支持,需要慎重使用;

加入收集器的参数配置用例如下:

-server -Xmx3550m -Xms3550m -Xmn1256m -Xss128k -XX:SurvivorRatio=6 -XX:MaxPermSize=256m   @b@@b@-XX:ParallelGCThreads=8 -XX:MaxTenuringThreshold=0 -XX:+UseConcMarkSweepGC

1.串行收集器

-XX:+UseSerialGC:设置串行收集器,其运行过程如下所示

Java垃圾回收器分类及相关参数配置说明

2.并行收集器(吞吐量优先)

-XX:+UseParallelGC:设置为并行收集器。此配置仅对年轻代有效。即年轻代使用并行收集,而年老代仍使用串行收集。

-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时有多少个线程一起进行垃圾回收。此值建议配置与CPU数目相等。

-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0开始支持对年老代并行收集。

-XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间(单位毫秒)。如果无法满足此时间,JVM会自动调整年轻代大小,以满足此时间。

-XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动调整年轻代Eden区大小和Survivor区大小的比例,以达成目标系统规定的最低响应时间或者收集频率等指标。此参数建议在使用并行收集器时,一直打开。

运行过程如下所示:

Java垃圾回收器分类及相关参数配置说明

3.并发收集器(响应时间优先)

-XX:+UseConcMarkSweepGC:即CMS收集,设置年老代为并发收集。CMS收集是JDK1.4后期版本开始引入的新GC算法。它的主要适合场景是对响应时间的重要性需求大于对吞吐量的需求,能够承受垃圾回收线程和应用线程共享CPU资源,并且应用中存在比较多的长生命周期对象。CMS收集的目标是尽量减少应用的暂停时间,减少Full GC发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代内存。

-XX:+UseParNewGC:设置年轻代为并发收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此参数。

-XX:CMSFullGCsBeforeCompaction=0:由于并发收集器不对内存空间进行压缩和整理,所以运行一段时间并行收集以后会产生内存碎片,内存使用效率降低。此参数设置运行0次Full GC后对内存空间进行压缩和整理,即每次Full GC后立刻开始压缩和整理内存。

-XX:+UseCMSCompactAtFullCollection:打开内存空间的压缩和整理,在Full GC后执行。可能会影响性能,但可以消除内存碎片。

-XX:+CMSIncrementalMode:设置为增量收集模式。一般适用于单CPU情况。

-XX:CMSInitiatingOccupancyFraction=70:表示年老代内存空间使用到70%时就开始执行CMS收集,以确保年老代有足够的空间接纳来自年轻代的对象,避免Full GC的发生,运行过程如下所示

Java垃圾回收器分类及相关参数配置说明

4.其它垃圾回收参数

-XX:+ScavengeBeforeFullGC:年轻代GC优于Full GC执行。

-XX:-DisableExplicitGC:不响应 System.gc() 代码。

-XX:+UseThreadPriorities:启用本地线程优先级API。即使 java.lang.Thread.setPriority() 生效,不启用则无效。

-XX:SoftRefLRUPolicyMSPerMB=0:软引用对象在最后一次被访问后能存活0毫秒(JVM默认为1000毫秒)。

-XX:TargetSurvivorRatio=90:允许90%的Survivor区被占用(JVM默认为50%)。提高对于Survivor区的使用率。

5.辅助信息参数设置

-XX:-CITime:打印消耗在JIT编译的时间。

-XX:ErrorFile=./hs_err_pid.log:保存错误日志或数据到指定文件中。

-XX:HeapDumpPath=./java_pid.hprof:指定Dump堆内存时的路径。

-XX:-HeapDumpOnOutOfMemoryError:当首次遭遇内存溢出时Dump出此时的堆内存。

-XX:OnError=";":出现致命ERROR后运行自定义命令。

-XX:OnOutOfMemoryError=";":当首次遭遇内存溢出时执行自定义命令。

-XX:-PrintClassHistogram:按下 Ctrl+Break 后打印堆内存中类实例的柱状信息,同JDK的 jmap -histo 命令。

-XX:-PrintConcurrentLocks:按下 Ctrl+Break 后打印线程栈中并发锁的相关信息,同JDK的 jstack -l 命令。

-XX:-PrintCompilation:当一个方法被编译时打印相关信息。

-XX:-PrintGC:每次GC时打印相关信息。

-XX:-PrintGCDetails:每次GC时打印详细信息。

-XX:-PrintGCTimeStamps:打印每次GC的时间戳。

-XX:-TraceClassLoading:跟踪类的加载信息。

-XX:-TraceClassLoadingPreorder:跟踪被引用到的所有类的加载信息。

-XX:-TraceClassResolution:跟踪常量池。

-XX:-TraceClassUnloading:跟踪类的卸载信息。

 6、其他更多配置

1、-XXThreadStackSize:@b@设置内存页的大小,不可设置过大,会影响Perm的大小@b@2、-XX:+UseFastAccessorMethods:@b@设置原始类型的快速优化@b@3、-XX:+DisableExplicitGC:@b@设置关闭System.gc()(这个参数需要严格的测试)@b@4、-XX:MaxTenuringThreshold@b@设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率。该参数只有在串行GC时才有效.@b@5、-XX:+AggressiveOpts@b@加快编译                 @b@6、-XX:+UseBiasedLocking@b@锁机制的性能改善                 @b@7、-Xnoclassgc @b@禁用垃圾回收                 @b@8、-XX:SoftRefLRUPolicyMSPerMB@b@设置每兆堆空闲空间中SoftReference的存活时间,默认值是1s 。(softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap)@b@9、-XX:PretenureSizeThreshold  @b@设置对象超过多大时直接在旧生代分配,默认值是0。@b@10、-XX:TLABWasteTargetPercent  @b@设置TLAB占eden区的百分比,默认值是1% 。  @b@11、-XX:+CollectGen0First     @b@设置FullGC时是否先YGC,默认值是false。@b@@b@@b@作者:零点145@b@链接:https://www.jianshu.com/p/4ff50dc13c1f@b@来源:简书@b@著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。