• 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调优的入门教程。

    参加Erlang开发者大会一些记录

    Erlang开发者大会是我参与过的最温馨的一个小规模会议,没有赞助商广告,不用抢网络,有免费午餐和下午茶(水果),第二天还有免费的中午大餐。感谢xushiwei和赞助商们(盛大,金山及 opengoss),让大家能够在这么一个温馨的场所进行交流。

    第一天有2个有关web game的session, 其中jackyz的麻将程序业务逻辑竟然是用JS完成的,“用Erlang写业务逻辑太繁琐了”,他是如是说。另外一个是金山的韩拓的基于Flash的象棋程 序,同时里面还实现了一个AI的机器人,他这个demo已经在google code上开源了,见 erl-chess

    前文提到过的一次演讲陈杰谈网游服务器的后端技术,演讲是在第一天下午分组讨论会上。分组讨论的遗憾是很难取舍,嫌自己分身无术。周敏的MapReduce和另外一个Topic Erlang VM我也很感兴趣,但没法同时参与了。

    另外还有几个相对深奥的Topic, 比如TrustNo1谈的冯诺依曼机的缺陷,Mryufeng的Inside the erlang VME2dynomo, 光听名字就很深奥。听众听完都没胆量提问了。

    尾声是在ery.lee讲的Erlang电信网管软件应用, EryLee走得比较前沿,他已经用Erlang开发出大规模的商用软件了。他讲述了他从繁琐的Java EE,SOA转向轻量级的Erlang后端+Ruby on Rails前端的经历。Ery的观点比较激进,但是我比较认可。他提到目前主流的应用程序实际上都是在处理数据,实际上是一个数据流的处理,但是使用流行 的OO方式去解决问题,首先经常考虑的却是我怎么样写一个class, 或者我要用一个什么样的设计模式。但是FP语言如Erlang从第一行开始就是对数据真正的业务处理,可以更精简的完成任务。

    其中我也很荣幸在大会中讲了一个XMPP Jabber的话题,于在场的开发高手进行了探讨,获益颇多。

    陈杰谈网游服务器的后端技术

    在12/20的Erlang开发者大会上,西山居的陈杰(bitcowboy)的演讲《网游服务端寻路》给我的印象非常深刻。他通过一个网游服务器寻路的案例,给大家讲述了在算法,架构,cache,并发编程及借鉴了Erlang的一些先进思路的各种经验及体会。

    • 算法,运营对寻路的要求比普通算法性能要高100倍。2D/3D中分别如何设计算法达到性能要求。
    • 稳定性
    1. 将独立的模块封装成单独的进程。
    2. 进程间通讯(IPC)使用TCP,为什么使用TCP而不是其他更高效的本地IPC方式?一方面因为大部分项目都有现成稳定的TCP模块,另外一方面更容易将一台服务器拆分到多个服务器,程序完全不用修改。
    3. 进程死掉怎么办?进程调用长时间不返回怎么办?
    4. 面对3的问题,旁边有另外一游戏架构设计师更是提到他们采取更激进的做法,将所有的进程做成单任务式的,完成任务就结束。分配任务线程为每个任务开新进程。有点象用Erlang中的process或Java中线程池的做法。
    • 一种多进程访问共享内存不需要加锁的设计模式,如图所示。

    调度进程

    (Figure: 来源陈杰PPT, 作者为陈杰)

    1. 调度进程给寻路进程分配任务,每次一个任务。
    2. 寻路进程更新cache为了避免并发访问,先只写入到 local cache
    3. 如果所有寻路进程空闲,调度进程会通知其中1个寻路进程将local cache同步到全局cache
    4. 如果一个寻路进程指定的时间没有返回,可简单kill之
    5. 此模式适合更多使用场合
    • 一种热升级模块的设计模式,简述:新进程使用新端口启用->通知调度启用新端口->调度程序将请求转向新端口->老模块完成手头工作后,被调度告知自动结束。

    总的说来,陈杰的演讲反应非常热烈,旁听参与的听众讨论也非常热烈,因为本人不是演讲者,很多细节没法在这里深入表达,PPT中也只是表达了现场的部分观点。

    另外这个演讲是以一个小组讨论的形式进行的,这样演讲者和听众的思路非常自由,比单独站台上讲相比可以进行更深入的交流。所以陈杰总是提醒大家,我们还是把这个演讲稿先讲完吧。

    对,我们也先把演讲稿看完把,Google Docs 在线预览版:网游服务端寻路