• Feeds

  • Java垃圾回收调优

    在Java中,通常通讯类型的服务器对GC(Garbage Collection)比较敏感。通常通讯服务器每秒需要处理大量进出的数据包,需要解析,分解成不同的业务逻辑对象并做相关的业务处理,这样会导致大量的临时对象被创建和回收。同时服务器如果需要同时保存用户状态的话,又会产生很多永久的对象,比如用户session。业务越复杂的应用往往用户session包含的引用对象就越多。这样在极端情况下会发生两件事情,long gc pause time 或 out of memory。

    一,要解决long pause time首先要了解JVM中heap的结构

    java gc heap

    java gc heap

    • Java Heap为什么要分成几个不同的代(generation)? 由于80%-98%的对象的生存周期很短,大部分新对象存放在young generation可以很高效的回收,避免遍历所有对象。
    • young与old中内存分配的算法完全不同。young generation中由于存活的很少,要mark, sweep 然后再 compact 剩余的对象比较耗时,干脆把 live object copy 到另外一个空间更高效。old generation完全相反,里面的 live object 变化较少。因此采用 mark-sweep-compact更合适。

    二,Java中四种垃圾回收算法

    Java中有四种不同的回收算法,对应的启动参数为
    –XX:+UseSerialGC
    –XX:+UseParallelGC
    –XX:+UseParallelOldGC
    –XX:+UseConcMarkSweepGC

    1. Serial Collector
    大部分平台或者强制 java -client 默认会使用这种。
    young generation算法 = serial
    old generation算法 = serial (mark-sweep-compact)
    这种方法的缺点很明显,stop-the-world, 速度慢。服务器应用不推荐使用。

    2. Parallel Collector
    在linux x64上默认是这种,其他平台要加 java -server 参数才会默认选用这种。
    young = parallel,多个thread同时copy
    old = mark-sweep-compact = 1
    优点:新生代回收更快。因为系统大部分时间做的gc都是新生代的,这样提高了throughput(cpu用于非gc时间)
    缺点:当运行在8G/16G server上old generation live object太多时候pause time过长

    3. Parallel Compact Collector (ParallelOld)
    young = parallel = 2
    old = parallel,分成多个独立的单元,如果单元中live object少则回收,多则跳过
    优点:old old generation上性能较 parallel 方式有提高
    缺点:大部分server系统old generation内存占用会达到60%-80%, 没有那么多理想的单元live object很少方便迅速回收,同时compact方面开销比起parallel并没明显减少。

    4. Concurent Mark-Sweep(CMS) Collector
    young generation = parallel collector = 2
    old = cms
    同时不做 compact 操作。
    优点:pause time会降低, pause敏感但CPU有空闲的场景需要建议使用策略4.
    缺点:cpu占用过多,cpu密集型服务器不适合。另外碎片太多,每个object的存储都要通过链表连续跳n个地方,空间浪费问题也会增大。

    几条经验:
    1. java -server
    2. 设置Xms=Xmx=3/4物理内存
    3. 如果是CPU密集型服务器,使用–XX:+UseParallelOldGC, 否则–XX:+UseConcMarkSweepGC
    4. 新生代,Parallel/ParallelOld可设大于Xmx1/4,CMS可设小,小于Xmx1/4
    5. 优化程序,特别是每个用户的session中的集合类等。我们的一个模块中session中曾经为每个用户使用了一个ConcurrentHashMap, 里面通常只有几条记录,后来改成数组之后,每台机大概节约了1~2G内存。

    不过总的说来,Java的GC算法感觉是业界最成熟的,目前很多其他语言或者框架也都支持GC了,但大多数都是只达到Java Serial gc这种层面,甚至分generation都未考虑。JDK7里面针对CMS又进行了一种改进,会采用一种G1(Garbage-First Garbage Collection)的算法。实际上Garbage-First paper(PDF) 2004年已经出来了,相信到JDK7已经可以用于严格生产环境,有时间也会进一步介绍一下G1。
    另外在今年的Sun Tech Days上Joey Shen讲的Improving Java Performance(PDF)也是一个很好的Java GC调优的入门教程。

    如想及时阅读Tim Yang的文章,可通过页面右上方扫码订阅最新更新。

    « | »

    Comments

    8 Comments

    1. xZeus

      java的gc调优需要分jvm版本的,ibm的jvm和sun的jvm的gc策略和架构就不一样,调优的方式也不一样,比如ibm的jvm在调整jvm的回收策略的时候调p簇和k簇,sun的就没有。

    2. 总结得好。

    3. 楼拴柱

      2. 设置Xms=Xmx=3/4物理内存

      这一条不太理解,物理内存指的是机器的总内存?

      我这台机器上要是想起多个虚拟机怎么办?且每个都需要一样的内存大小,怎么分配,不能一个就占物理内存的3/4吧

    4. 楼拴柱

      5. 优化程序,特别是每个用户的session中的集合类等。我们的一个模块中session中曾经为每个用户使用了一个ConcurrentHashMap, 里面通常只有几条记录,后来改成数组之后,每台机大概节约了1~2G内存。

      这个太诧异了,每个用户存一个ConcurrentHashMap,这么浪费内存的事情是怎么想出来的

    5. […] 原文地址http://timyang.net/java/java_gc_tunning/ 除非注明,本站所有文章均为原创,互联分享,尊重版权,转载请注明 . 原文链接: http://www.onion.im/share/java/java%e5%9e%83%e5%9c%be%e5%9b%9e%e6%94%b6%e8%b0%83%e4%bc%98%e3%80%90%e8%bd%ac%e3%80%91 版权所有: Onion […]

    6. […] 如何设置可以参考新浪timyang的博客:Java垃圾回收调优,这是个09年的文章,现在是不是有新的垃圾回收的策略了呢。 […]

    7. […] Java垃圾回收调优 Wednesday, Jan 7th, 2009 by Tim | Tags: GC, Java […]

    8. […]     学会从别人的源码中吸收力量,例如:ConcurrentHashMap的分离锁的实现的思想,仅仅会简单使用这个类后续肯定会给你带来麻烦的,比较在这个类中装了太多的东西,肯定是很耗内存的(杨老师的文章上提到过) […]

    Leave a Comment

    Your email address will not be published. Required fields are marked *