优化系统Performance小记

我的系统是一个Server,每个用户每次服务要做很多事情,大概需要内存10MB-20MBServer里有很多服务,每个服务可能会有多个实例在跑。每次跑需要1分多钟。所以一般情况,开一宿机器就崩。

这应该有内存泄漏问题,很有可能使一些该释放的东西没有释放(包括内存、线程、资源、锁等等),导致了系统崩溃。对于内存不能正常释放,最该注意的就是Singleton,或者那些生命周期很长的instance。最该注意的就是那些Collection,很可能是put进去的对象没有remove

做内存泄漏检查的简单的方法就是用Profiler,比如JProfiler,这里要求我们写Collection的时候有一个Trick,就是我们要put我们自己的MyClassObject,而尽量少用基础类型的对象,至少至少要包一层我们的MyClass。这是因为Profiler统计的是每个类型的对象个数和所占空间。每个Collection有自己的MyClass,方便了分开统计,如果都用String,统计结果根本不能告诉我们哪漏了。通常情况下Profiler统计结果中String的量远大于其他。

另一个简单的检查方式就是审查代码,操作Collection要规范,负责put的就要负责remove,要符合谁申请谁释放的原则。Cache要有合理的淘汰算法。

经过上面的调整,句柄都规规矩矩的释放了。可是系统还是很慢,这就涉及到GC的问题了。如果最大堆设为1GB的话,Java就喜欢在占据内存800MB左右的时候开始大量调用GC,维持JVM的可用内存在20%左右,有时候服务少,GC一下能有50%的可用内存也就是500MB。而这时操作系统的性能很低,主要原因不是JVM垃圾回收有问题,而是操作系统的可用内存不多了!JVM和系统要了内存之后不知道归还,操作系统一共就2GB内存,JVM要了1GB,操作系统就慢了,也就影响的Server系统慢了。貌似最大堆设为512MB也许还可取,但这仍然有问题。假设有20%的可用内存即100MB,这时同时跑起来几个服务,那GC可就够忙活的。所以保证20%可用内存是不可取的。

那我们有两个做法,一个是改JVM的参数,使它能早一些回收老龄的内存;另一个做法就是在每一次服务结束之后调用GC。一次服务之后,十多MB内存的东西可以说就彻底没用了,调用GC回收或许还算可以接受?目前是用这种方式,还应该有其他的方式可以优化。

但是这里面有问题:GC是不可靠的,调用GC只是建议,一般情况,GC应该听从建议的,但还是要考虑到如下两个特殊问题:

第一,   假设一个对象开启了一个线程,但没有写如何结束这个线程,当这个对象被回收之后,线程就没人管了,如果这种对象频繁被实例化,那些野线程就会很多很多,五十步笑百步,如果在finalize方法里写了终止线程,那就是要GC保佑了;

第二,   假设一个对象是一个临界资源的访问者,如果这个对象在一个线程中被实例化、获得资源访问权、使用,并且在finalize方法中写了如何释放资源,最后交给了GC。注意!释放资源的方法写在了finalize里!那么另一个线程申请这个对象的时候就需要等待上一个对象的回收,等待GC?。。。可能一百年也等不来L。所以我们不能这么用资源。

Java提供的机制让我们不需要完整的关心一个对象的生命周期,但是各种资源的生命周期还是我们要管的,资源在使用完之后还是要释放,就像C++里的newdelete,似乎把一切都交给GC有些不负责任。我相信一定会有一些模式,能够让我们轻松的管理资源的生命周期,依靠这些模式,我们再去用GC管理无用内存,心里就有底了。

这次优化就到这里,很多问题还没解,暂时交给GC了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值