您的位置:网站首页 > Java工具 > 正文

东方龙马 慎用javalangrefSoftReference实现缓存

类别:Java工具 日期:2017-10-17 16:58:28 人气: 来源:

  在JVM内部实现缓存容器,东方龙马认为最麻烦的事情是要对缓存大小进行控制。为何这样说?当我们缓存的是一些值对象(ValueObject)时,一个难点是计算这一些对象(及对象引用的大小)。JVM的API并没有赋予我们通过简单的调用即可获得对象(及其引用)大小的能力。当然,你可以通过ObjectOutputStream又或者自定义的方式将对象转换成二进制数据[bytes],从而做到精确控制缓存占用的内存,但是带来的一个问题是对象的序列化与反序列化带来的开销。

  这是使用最普遍的引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。

  强引用的例子:方法局部变量、JNI变量、类变量,概括起来,就是所有GC Root引用可达的都是强引用;

  如果一个对象只具有软引用,那就类似于可有可无的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存的高速缓存。

  软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

  如果一个对象只具有弱引用,那就类似于可有可无的生活用品。 弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。

  弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

  虚引用顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。

  虚引用主要用来对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃 圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采 取必要的行动。

  某用户使用Gerrit2作为其代码管理的工具。系统运维工程师反映,近期系统在运行过程中频繁出现性能问题,最终用户使用系统时经常出现挂起(无响应)。运行如下:

  接到这个问题,遵循既定的思,让用户做一定的准备,调整JVM的参数捕获故障时的现场信息进行问题分析。最后定位为JVM Heap频繁的Full GC问题导致应用出现性能故障,参考如下:

  JVM GC日志显示,每一次GC以后,JVM Heap空闲的空间仍然有1GB以上的空间可用;

  原始的JVM GC日志显示,在故障时间点附近,有非常频繁的Full GC,触发的原因为JVM Old区满,并且每次Full GC后,Old区能出来的空闲空间相当少;但是整个JVM总计的空闲Heap仍然有1GB以上的空间。

  笔者尝试分析一下缓存的机制,容器组件RepositoryCache以及WindowCache 其使用的是正是java.lang.ref.SoftReference对缓存对象进行引用。并且,RepositoryCache组件没有缓存消耗机制(例如缓存的对象的数量或者缓存总计大小),而WindowCache组件虽然有控制缓存文件数量及总计内存大小,但是最终的结果与实际想要控制的差距太大,并未如设想那样有效地控制内存消耗。

  既然程序是使用java.lang.ref.SoftReference保持对缓存对象的引用,参考原来Sun的说法,如果一个对象只有软引用可达,在内存不足时,是可以被回收的,那关键的问题是JVM的GC如何判定这个SoftReference引用的对象何时被回收?

  是否保留SoftReference引用对象的判断参考表达式,true为不回收,lse 为回收:

  东方龙马上述的判断简单地理解就是:如果SoftReference引用对象的时长=空闲内存可保持软引用的最大时间范围,则不清除SoftReference所引用的对象;否则,则将其清除;

  参考上述的理论,我们大概可以估算一下当一个对象仅有SoftReference引用可达时,其最大生命的周期情况:

  设置较大的JVM Heap时,因为Sun的New Generation与Old Generation比例关系,每一次GC以后,New Generation出来的空闲空间的数量,总是使SoftReference引用的对象的周期保持在一个较大的值,换言而之,其淘汰的速度较慢。而Old Generation满频繁触发的Full GC以及内存碎片整理,使得整个JVM非常卡顿;

  而设置更大的JVM Heap后,使得每一次GC以后,New Generation出来的空闲空间的数量更多,从而加剧了这种故障的情况;

  推荐:

  

关键词:java缓存清理
0
0
0
0
0
0
0
0
下一篇:没有资料

网友评论 ()条 查看

姓名: 验证码: 看不清楚,换一个

推荐文章更多

热门图文更多

最新文章更多

关于联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 人才招聘 - 帮助

郑重声明:本站资源来源网络 如果侵犯了你的利益请联系站长删除

CopyRight 2010-2012 技术支持 FXT All Rights Reserved