1、GC & JAVA TOOLS,谢刚 2009-7-27,GC,GC是一个自动管理内存的程序。主要职责是分配内存,保证被引用的对象始终在内存,把不被应用的对象从内存中释放GC会自动计算对象被引用的情况,只要对象不再被引用,相应的内存就会被回收,另外,GC非常重要的一点就避免内存碎片,道理跟windows的磁盘整理一样,把使用中各个内存块整合起来,这样才能保证有足够的空间来存储大对象。,理想中的GC,该回收的回收,不该回收的绝不回收 GC要快而且GC运行时,不能导致应用程序的停顿。 限制内存碎片,对象被回收以后,所使用的内存会被回收,如果不加处理内存中就会出现大量的内存碎片,这样就有可能导致因为
2、没有足够的连续空间分配给某些大对象而导致OutofMemory。消除内存碎片的的手段之一就是“内存压缩”。 可扩展性(Scalability),内存的分配和回收都不能成为应用程序的瓶颈,GC的性能评判标准,吞吐量(Throughput)全部时间中不用于GC的比例。(重点) 暂停时间GC过程中应用程序执行暂停的时间。(重点) GC的开销全部时间中用于GC的比例。 GC的频率通过跟应用程序的执行比较来得到GC的执行频率。 支持GC运行所需使用的内存大小例如heap的大小。 GC的及时性(Promptness)一个对象从被废弃到内存被回收之间的时间差,堆(HEAP),JVM管理的内存叫堆。在32Bi
3、t操作系统上有4G的限制,而64Bit的就没有。 JVM初始分配的内存由-Xms指定,默认是物理内存的1/64但小于1G。 JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4但小于1G。-XX:MinHeapFreeRatio=40 -XX:MaxHeapFreeRatio=70 服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小,收集算法(一),复制(copy):将堆内分成两个相同空间,从根(ThreadLocal的对象,静态对象)开始访问每一个关联的活跃对象,将空间A的活跃对象全部复制到空间B,然后一次性回收整个空间A 优点:遍历对象成本小,由于只遍历活跃对象 缺
4、点:复制成本高,需要较多的内存,标记清除(mark-sweep):收集器先从根开始访问所有活跃对象,标记为活跃对象。然后再遍历一次整个内存区域,把所有没有标记活跃的对象进行回收处理。优点:不用复制缺点:遍历整个空间的成本较大暂停时间随空间大小线性增大,而且整理后堆里的碎片很多。,收集算法(二),标记整理(mark-sweep-compact) 这个算法有个阶段,mark(标识回收对象),sweep(清除),compact(压缩)。 综合前两者的做法和优点,先标记活跃对象,然后将其合并成较大的内存块,收集算法(三),分代( Generations ),分代根据对象的生命周期长短,把堆分为3个代:
5、 Young(年轻代、新生代)Old(年老代、老生代)Permanent(永生代)优点:根据不同代的特点采用不同的收集算法,扬长避短,堆内存分布图,-Xms1024m -Xmx1024m 堆大小 -XX:NewSize=256m -XX:MaxNewSize=256m 新生代大小 -XX:PermSize=128m -XX:MaxPermSize=128m 永生代大小 -Xss128K 单线程栈的大小-XX:MaxTenuringThreshold=2 新生代对象经过2次进入老年代,YOUNG,Young(Nursery),年轻代。研究表明大部分对象都是朝生暮死,随生随灭的。因此所有收集器都为
6、年轻代选择了复制算法。 Young里面又分为3个区域,一个Eden,所有新建对象都会存在于该区,两个Survivor区,用来实施复制算法。每次复制就是将Eden和第一块Survior的活对象复制到第2块,然后清空Eden与第一块Survior。 由于新生代的空间通常都比较小而且可能存在大量不再被引用的对象,所以针对新生代的GC执行频率高、速度快。,Old(Tenured),年老代,Old(Tenured),年老代。年轻代的对象如果能够挺过数次收集,就会进入年老代。年老代使用标记整理算法。因为年老代的对象都没那么容易死的,采用复制算法就要反复的复制对象,很不合算,只好采用标记清理算法,但标记清理
7、算法其实也不轻松,每次都要遍历区域内所有对象-XX:MaxTenuringThreshold=2 Perm(permanent ),永生代。例如类和方法对象以及它们的描述对象。,串行收集器(Serial Collector),新生代串行新生代串行收集老生代和永生代的串行收集(mark-sweep-compact),只使用一个cpu,并且回收时,应用程序会暂停 -XX:+UseSerialGC,并行收集器(Throughput Collector),新生代并行收集,stop-the-world和coping收集器,但是多线程年老代和永生代任然串行(mark-sweep-compact),-XX:
8、+UseParallelGC -XX:+UseParallelOldGC(并行压缩回收器) -XX:ParallelGCThreads= -XX:MaxGCPauseMillis= -XX:GCTimeRatio=,并发Mark-Sweep收集器(CMS),CMS的新生代回收收集的方式和并行回收一致 CMS的老生代回收,-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=60 -XX:CMSFullGCsBeforeCompaction
9、=5 -XX:+UseCMSCompactAtFullCollection,吞吐量优先,java - server -Xloggc:gc.log -Xmx1024m - Xms1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=128m -XX:MaxPermSize=128m -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=8 -XX:+UseParallelOldGC,短暂停优先,java -server -Xloggc:gc.log- Xmx1024m -Xms1024m -X
10、X:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=128m -XX:MaxPermSize=128m -Xss128k -XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=8 -XX:+UseParNewGC-XX:CMSInitiatingOccupancyFraction=60-XX:+CMSParallelRemarkEnabled-XX:+UseCMSCompactAtFullCollection(可选)-XX:CMSFullGCsBeforeCompaction=5(可选),其他参数,-XX:+Pr
11、intGCDetails -XX:+PrintGCTimeStamps -XX:+DisableExplicitGC -Xloggc:filename,JAVA TOOLS,jinfo jps Jstat jmap Jconsole jstack,JSTAT,一个极强的监视VM内存工具。可以用来监视VM内存内的各种堆和非堆的大小及其内存使用 jstat -class pid:显示加载class的数量,及所占空间等信息。 jstat -compiler pid:显示VM实时编译的数量等信息。 jstat -gc pid:可以显示gc的信息,查看gc的次数,及时间。其中最后五项,分别是young
12、gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。 jstat -gccapacity:可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小,如:PGCMN显示的是最小perm的内存使用量,PGCMX显示的是perm的内存最大使用量,PGC是当前新生成的perm内存占用量,PC是但前perm内存占用量。其他的可以根据这个类推, OC是old内纯的占用量。 jstat -gcnew pid:new对象的信息。 jstat -gcnewcapacity pid:new对象的信息及其占用量。 jstat -gcold pid:old
13、对象的信息。 jstat -gcoldcapacity pid:old对象的信息及其占用量。 jstat -gcpermcapacity pid: perm对象的信息及其占用量。 jstat -printcompilation pid:当前VM执行的信息。,JMAP,显示java进程内存使用的相关信息 jmap pid 打印内存使用的摘要信息jmap heap pid java heap信息jmap -histo:live 统计对象count ,live表示在使用 jmap -histopid mem.txt 打印比较简单的各个有多少个对象占了多少内存的信息,一般重定向的文件 jmap -du
14、mp:format=b,file= mem.dat pid 将内存使用的详细情况输出到mem.dat 文件用jhat命令可以参看 jhat -port 7000 mem.dat然后使用:http:/10.10.92.119:7000/ 查看类相关信息,JINFO,能输出并修改运行时的java进程的运行参数 jinfo -flag pid 打印name的值jinfo -flag +|- pid 取消或者设置某个属性jinfo -flag = pid 设置属性值 jinfo -flags pid 输出所有属性值jinfo -sysprops 输出JAVA属性 jinfo pid 输出所有的,jco
15、nsole,是一个用java写的GUI程序,用来监控VM,并可监控远程的VM 服务器端配置: mkdir $JAVA_HOME/jconsole_pwdcp $JAVA_HOME/jre/lib/management/jmxremote.password.template $JAVA_HOME/jconsole/jmxremote.password - chmod 600 $JAVA_HOME/jconsole/jmxremote.password vi jmxremote.password 去掉#monitorRole RED前的注释并将RED修改为你要设置的密码。(安全起见,只开放有只读权
16、限的用户) 修改 $RESIN_HOME/bin/wrapper.pl,为$JAVA_ARGS添加三个参数: JAVA_ARGS=“$JAVA_ARGS -Dcom.sun.management.jmxremote.port=1010 -Dcom.sun.management.jmxremote.password.file=/usr/local/jdk/jconsole/jmxremote.password -Dcom.sun.management.jmxremote.ssl=false“-Dcom.sun.management.jmxremote.ssl=false 执行hostname -
17、i ,如果显示的是127.0.0.1,则需要修改/etc/hosts文 vi /etc/hosts,修改如下: #127.0.0.1 localhost localhost.localdomain localhost 服务器的真实IP地址 localhost localhost.localdomain localhost,JSTACK,jstack - 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。 jstack工具还可以附属到正在运行的java
18、程序中,看到当时运行的java程序的java stack和native stack的信息 jstack -l 连接正在运行的进程jstack -F -m -l 连接挂起的进程 jstack -m -l 连接core文件 jstack -m -l server_id 连接远程服务器,参考资料,Tuning Garbage Collection with the 5.0 Java Virtual Machine 官方指南。 Hotspot memory management whitepaper 官方白皮书。 Java Tuning White Paper 官方文档。 FAQ about Garbage Collection in the Hotspot 官方FAQ,JVM1.4.2。 Java HotSpot 虚拟机中的垃圾收集 JavaOne2004上的中文ppt A Collection of JVM Options JVM选项的超完整收集。 http:/ JDK5.0垃圾收集优化之-Dont Pause http:/ JVM调优总 http:/www.daniel- Java内存管理 http:/ jstat:http:/ jmap:http:/ jconsole:http:/