我最近做的一个项目,在性能上有严重的问题,希望大家给些建议。情况如下:一个java程序,需要不断地从服务器上接收信息(一些二进制数据),并且把它们缓存在内存中。(一个hashmap来放它们)
每个二进制数据的大小大约0.5K,每秒约80个。
这些二进制数据被解析后,每一个都会生成一个对象,但每个对象内部都有一些更小的对象的引用,来表示信息内容,平均下来每个信息大约有20个这样的小对象。在生成对象的过程中,有大量的短命对象生成。
一天下来,大约会收到500000个这样的信息。合计起来,每天大约有250M左右的内存被固定占用。
有500000个这样的信息对象和500000*20个小对象被一直引用。我使用默认运行方式(使用JVM默认参数),很快就CPU100%,程序运行很慢,不一会儿就outofmemory。
后来改成了-verbose:gc -Xms60M -Xmx512M,发现在接收前5000个信息时很快,只有少量gc。但是超过5000后,系统就非常慢,并且在不断的fullgc,经常连续好几个。我反复检查了程序,没有发现内存泄漏,估计关键在于JVM的参数设置上,但是不会,希望大家给点意见!

解决方案 »

  1.   

    建议通过修改程序或者增加硬件来解决
    硬件的话增加内存就好了内存修改为: -Xms250M -Xmx1025M你看看你的java实际占用了多少内存?
      

  2.   

    JAVA的内存泄露往往很难检查,我还是觉得再好好查查那个hashtable的使用。
      

  3.   

    我的电脑内存为1G,服务器上好像是4G,但是现在还不能拿到服务器上测试。我把参数改为-server -verbose:gc -Xms32M -Xmx800M -XX:NewRatio=3 -XX:PermSize=32m -XX:MaxPermSize=150m 好了很多,直到收到近20000万条信息时,才感觉变慢。在此期间,系统很少Full gc,这点我比较满意。但是有一个问题就是,普通的gc开始很快,但后来就越来越慢,从几毫秒变成20、30、后来直到70、80毫秒,感觉就有点卡了。应该怎么解决这个问题?还有,eden区、survivor区、spaces区与成熟区它们之间的大小比例关系,对垃圾回收有什么影响?
      

  4.   

    拆墙补漏而已,你一再的加大JVM的内存使用大小,只是延长你OUTOFMENMORY发生的时间而已
    关键是看你程序,为社么会占用这么多的资源.优化程序(STRING边STRINGBUILDER?之类)或换个思路
      

  5.   

    这种事情不能靠Java程序的垃圾收集器来处理你的,象你这样的程序,你需要自己管理你的内存,将暂时不需要的内容放入硬盘中,算法可以参考操作系统同关于内存交换的算法,比如最近最久不用算法等等,当然这样的算法自己实现起来有一定难度,而且效果未必很好,毕竟有很多细节问题很难考虑周全。那么你可以考虑一下使用一个内存数据库来存储你的内容,例如hsql或者 berkly db等。最后,添个广告,在上海想学习Java技术的人可以到 www.javaedu.com.cn 来看看。
      

  6.   

    to shjavaedu使用内存数据库与直接用hashmap缓存,在性能上有什么区别?
      

  7.   

    忘了强调一点,这个程序又相当于一个server,对于其它机器发来的请求,要以最快的速度把缓存的信息转发过去,所以得保证它们一直在内存中(这样才快),不然我就可以使用数据库等方式保存了。前面有朋友提到了内存数据库,不知道它是否可以解决这种问题?
      

  8.   

    用JRockit看看,另外你的JDK版本是多少?用JRMC进行监控一下,应当有效果。
      

  9.   

    既然你要做server,你更不能只用hashmap来做这件事情,否则多少内存可能也不够。
      

  10.   

    重新修改了程序,性能有了很大的改观,现在使用-server -verbose:gc -Xms60M -Xmx800M -XX:NewRatio=3 -XX:PermSize=32m -XX:MaxPermSize=300m 已经可以轻松的收取300000万条以上的信息,而且CPU的占用率也不是很高。主要的修改是直接把收到的二进制数组以byte[]方式放入hashmap,而不是那个message对象。需要用的时候,再取出来临时构造一个message对象出来。又根据情况简化了一些函数。虽然没有以前看起来那么结构清晰,但是效率确实是提高的相当大。谢谢各位的帮助!