知晓JVM系列(二):JVM内存管理机制与优化初探

来源:互联网 发布:众筹网络大电影 编辑:程序博客网 时间:2024/05/22 12:19
1.GC初探:
    JVM的堆内存是程序开发常用到一块可以自己操作的内存区域,我们经常使用new产生的实例都存放在这片区域。正因为这块区域的自由度极高,所以管理起来也是相当的麻烦,所以JVM才设计了这一个GC机制帮助程序员进行内存管理,减少程序员手动的去管理内存带来的不必要的麻烦,提高内存使用效率和安全性。
   JVM内存大小:限制于实际的最大物理内存,其限制因素跟其寄宿的操作系统的位数有关。JVM堆内存的初始分配由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由 -Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆 直到-Xms的最小限制
   JVM堆内存结构如下:

 JVM内存分配方式:
    1、对象优先在EDEN分配
    2、大对象直接进入老年代 
    3、长期存活的对象将进入老年代 
    4、适龄对象也可能进入老年代:动态对象年龄判断
     GC(Garbage Collection)机制主要针对的是JVM中的堆内存,GC不会对非堆内存进行清理和回收。GC的回收内存机制是根据JVM堆内存模型来设计的,而整个堆内存模型的空间分配是满足对象的生命周期模型的。所以GC机制主要操作的内存区域有Eden pool、survivor from、survivor to、Tenured这四块内存区域,Eden与survivor同属于一个代区:Youth generation ,Tenured 属于Old generation。

2.常见GC算法:
       注:GC不是固定的,在不同的环境下,其实现原理和算法不一样。如net与jvm
        1.    引用计数(Reference Counting) 
               比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对象。此算法最致命的是无法处理循环引用的问题。 
        2.    标记-清除(Mark-Sweep) 
               此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。 
        3.    复制(Copying) 
               此 算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。次算法每次只处理 正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不过出现“碎片”问题。当然,此算法的缺点也是很明显的,就是需要两倍 内存空间。 
       4.    标记-整理(Mark-Compact) 
              此算法结合了“标记-清除”和“复 制”两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象“压缩”到堆的其中一 块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。 
        5.    增量收集(Incremental Collecting) 
实施垃圾回收算法,即:在应用进行的同时进行垃圾回收。不知道什么原因JDK5.0中的收集器没有使用这种算法的。 
        6.    分代(Generational Collecting) 
              基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法(上述方式中的一个)进行回收。现在的垃圾回收器(从J2SE1.2开始)都是使用此算法的。
3.GC种类
       1.单线程收集器(serial collector
             特点:使用单线程去完成所有的gc工作,没有线程间的通信,这种方式会相对高效,Client模式下默认。
       2.并行收集器parallel collector或叫throughput collector 
             特点:使用多线程的方式,利用多CUP来提高GC的效率主要以到达一定的吞吐量为目标,但是只在young area使用使用多线程Server模式下默认。
       3.并发收集器concurrent collector或叫concurrent low pause collector
             特点:使用多线程的方式,利用多CUP来提高GC的效率并发完成大部分工作,使得gc pause短。
4.GC类型
       1.    Scavenge GC (YGC)
              一般情况下,当新对象生成,并且在Eden申请空间失败时,就好触发Scavenge GC,堆Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。 
      2.    Full GC (FGC)
              对整个堆进行整理,包括Young、Tenured和Perm。Full GC比Scavenge GC要慢,因此应该尽可能减少Full GC。有如下原因可能导致Full GC
5.衡量GC的指标(GC Metrics) 
  • Throughput(吞吐量):所有没有花在执行GC上的时间占总运行时间的比重。
  • Pauses(暂停):当GC在运行时程序的暂停次数。或者是在感兴趣的暂停次数中,暂停的平均时长和最大时长。
  • Footprint(足迹?):当前使用的堆内存大小。
  • Promptness(及时性):不再使用的对象多久能被清除掉并释放其内存。
6.GC中对象的可触及状态
     GC中对象的六种可触及状态

   1.强可触及:对象可以从根结点不通过任何引用对象搜索到

   2.软可触及:对象不是强可触及的,但是可以从根结点开始通过一个或多个(未被清除的)软引用对象触及

   3.弱可触及:对象既不是强可触及也不是软可触及的,但是从根结点开始可以通过一个或多个弱引用对象触及

   4.可复活的:对象既不是强可触及、软可触及,也不是弱可触及,但是仍然可能通过执行某些终结方法复活到这几种状态之一

   5.影子可触及:不上以上任何可触及状态,也不能通过终结方法复活,并且它可以从根结点开始通过一个或多个影子引用对象触及(影子引用不会被垃圾收   集器清除,由        程序明确地清除)

   6不可触及:就是已经准备回收的状态 

7.GC过程

8.优化机制与操作
       在Dos下使用java -X命令,查看具体配置命令
       
       1.调整JVM堆内存各代空间比例与栈空间大小
             (1). java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
                          -Xmx3550m:设置JVM最大可用内存为3550M。 
                          -Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。 
                          -Xmn2g:设置年轻代大小为2G。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代   
                                       后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。 
                          -Xss128k: 设置每个线程的堆栈大小。
              (2).java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0 
                         -XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为 
                                                      1:4,年轻代占整个堆栈的1/5 
                         -XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个 
                                                           Survivor区占整个年轻代的1/6 
                         -XX:MaxPermSize=16m:设置持久代大小为16m。 
                         -XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代 
                                                                           比较多的应用,可以提高效率。
       2.根据应用规模选择GC种类
              (3). java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 
                           -XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用 
                                                             串行收集。 
                          -XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。 
              (4).java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC
                          -XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集。
              (5).java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC  -XX:MaxGCPauseMillis=100
                          -XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。 
              (6).java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC  -XX:MaxGCPauseMillis=100 -XX:+UseAdaptiveSizePolicy 
                          -XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最   
                                                                         低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。
                          -XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。 
                          -XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩       
               (7).Incremental mode
             -XX:+CMSIncrementalMode default: disabled 启动i-CMS模式(must with -XX:+UseConcMarkSweepGC)
                          -XX:+CMSIncrementalPacing default: disabled 提供自动校正功能
                          -XX:CMSIncrementalDutyCycle=<N> default: 50 启动CMS的上线
                          -XX:CMSIncrementalDutyCycleMin=<N> default: 10 启动CMS的下线
                          -XX:CMSIncrementalSafetyFactor=<N> default: 10 用来计算循环次数
                          -XX:CMSIncrementalOffset=<N> default: 0 最小循环次数(This is the percentage (0-100) by which the incremental mode duty  
                                                                                                cycle is shifted to the right within the period between minor collections.)
                          -XX:CMSExpAvgFactor=<N> default: 25 提供一个指导收集数
       3.调整GC清理的时间间隔
                           -XX:+UseParNewGC此命令可以加快minor收集时间。
                           -XX:+UseConcMarkSweepGC -XX:+UseParNewGC此命令可以加快major收集时间
       4.根据具体情况选择GC的算法
       5.垃圾回收统计信息 
                          -XX:+PrintGC 
                          -XX:+PrintGCDetails 
                          -XX:+PrintGCTimeStamps 
                          -Xloggc:filename
                          注:在java -X中并没有-XX命令,此时用 java -verbose:gc -XX:+PrintGCDetails
        6.JVM运行模式选择:
                 (1).java -client
                 (2).java -server
        7.常用监测工具
              jconsole JDK自带的内存监测工具,路径jdk bin目录下jconsole.exe,双击可运行。
              jvisualvm JDK自带的监测工具,路径jdk bin目录下jvisualvm .exe,双击可运行。
              jvmstat  jvmstat是图形版的jstat,由Java 官方提供,目前最新版本为3.0。
              YourKit Java Profiler   YourKit 是一个用于分析Java 与.NET 应用程序的智能工具,YourKit Java Profiler 已经被IT 专业人士与分析师 
                                                      公认为最好的分析工具。通过YourKit 技术解决方案可以以非常高的的专业水平分析出CPU 与内存使用情况。
              
              JProfiler 收费的工具,但是到处都有破解办法。安装好以后按照配置调试的方式配置好一个本地的session即可运行。
              jinfo 可以从一个给定的java进程或core文件或远程debug服务器上获取java配置信息。包括java系统属性及JVM参数(command line flags)。
              jmap 观察运行中的jvm物理内存的占用情况。
              jps 列出所有的jvm实例
              jvmtop 一个轻量级的控制台程序用来监控机器上运行的所有 Java 虚拟机。
              jstack 观察jvm中当前所有线程的运行情况和线程当前状态
              jstat JVM监测工具(Java Virtual Machine Statistics Monitoring Tool)。利用了JVM内建的指令对Java应用程序的资源和性能进行实
                                                     时的命令行的监控,包括各种堆和非堆的大小及其内存使用量、classloader、compiler、垃圾回收状况等。
             Java api方式监测jre中提供了一些查看运行中的JVM内部信息的api,这些api包含在java.lang.management包中,此包中的接口 
                                        是在jdk 5中引入的,所以只有在jdk 5及其以上版本中才能通过这种方式访问这些信息。
          
参考文章:
            http://www.cnblogs.com/redcreen/archive/2011/05/04/2037029.html
            http://blog.csdn.net/ithomer/article/details/6252552
            http://hi.baidu.com/qust409xls/item/d013eb1126f0c30f8ebde4a6
            http://blog.chinaunix.net/uid-7374279-id-4489100.html
            http://zhangjiangxing-gmail-com.iteye.com/blog/1048832
            http://blog.csdn.net/kobejayandy/article/details/8496663
            http://www.cnblogs.com/hnrainll/archive/2013/11/06/3410042.html
            http://wenku.baidu.com/view/de4b06a8dd3383c4bb4cd235.html
            http://www.cnblogs.com/xianrongbin/archive/2011/11/27/2265157.html
            http://www.cnblogs.com/redcreen/archive/2011/05/04/2037029.html
            http://blog.csdn.net/lengyuhong/article/details/5953544
            http://www.cnblogs.com/redcreen/archive/2011/05/09/2040977.html
            http://286.iteye.com/blog/1931574
            http://developer.51cto.com/art/201009/227512.htm
            http://my.oschina.net/timer/blog/10599
           

            

0 0