`
BradyZhu
  • 浏览: 247742 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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

 
阅读更多
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算法
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,双击可运行。
jvisualvmJDK自带的监测工具,路径jdk bin目录下jvisualvm.exe,双击可运行。
jvmstatjvmstat是图形版的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中当前所有线程的运行情况和线程当前状态
jstatJVM监测工具(Java Virtual Machine Statistics Monitoring Tool)。利用了JVM内建的指令对Java应用程序的资源和性能进行实
时的命令行的监控,包括各种堆和非堆的大小及其内存使用量、classloader、compiler、垃圾回收状况等。
Java api方式监测jre中提供了一些查看运行中的JVM内部信息的api,这些api包含在java.lang.management包中,此包中的接口
是在jdk 5中引入的,所以只有在jdk 5及其以上版本中才能通过这种方式访问这些信息。

参考文章:
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics