实战SoftReference被回收的时机

这是我最近在开发的一个基于客户端发现模式(因为基于服务端发现的都比较多了,consul还做得很好)的服务注册发现框架:

  https://github.com/leoChaoGlut/ServiceDIscoveryAndRegistry


然后在过程中遇到这样一个问题:


在做client-service-proxy的时候,要实现一个负载均衡算法.


我选了比较常用的轮询分发算法.


在实现过程中,需要将发送过的相同的host和port缓存下来,以便不要再次分发到相同的节点.如果一个服务的所有节点都发送过了,则会清理缓存,重新轮询.


问题来了,实现缓存,如果直接用new HashSet()这样的方式存储,如果内部的元素一直被引用,和GC Root一直有通路,则该对象不会被GC.


但有时候该对象其实又不会经常被用到,存着还是浪费内存.


所以一般会用SoftReference<Set<T>>软引用方式来做缓存容器.


SoftReference的源码介绍里也有提到,它可以被用作memory-sensitive caches.


问题又来了,SoftReference被GC的情况和想象中不一样!!!!!!!!!!!!!


我在测试的时候,用VisualVM来监控测试程序,当我利用VisualVM手动执行Full GC时,SoftReference竟然没有被GC!!!!!!!!


于是乎我又去看了源码的解释,如下:


All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an <code>OutOfMemoryError</code>.


意思是在OOM发生之前,它才会被GC掉,而没有发生OOM之前的GC,是不会将SoftReference的对象GC掉的!


会导致的问题:

SoftReference<Set<String>> recordSetRef = new SoftReference<>(new HashSet<>());//1
Set<String> recordSet = recordSetRef.get();//2
if (recordSet.isEmpty()) {//3. 如果运气非常不好...这里可能会报空指针.因为执行到上面那一句的时候,该线程正好失去CPU时间片,且正好即将发生OOM(正常的GC不会清理SoftReference),则此时recordSet会是null
}

根据Java 内存模型:一个代码块内,如果前后的代码不存在关联关系,则可能会发生指令重排序.(当然,上例中没有出现指令重排序).


当然,一个线程对应一个方法栈,如果两个线程之间的数据没有依赖关系,也是不会发生并发线程安全问题的.


如果要避免这样的情况,可以将该代码块用synchronized包裹起来,如果频繁被调用的话,不建议加锁,应该另辟出路.


因为加了锁,就算当前线程失去时间片,在该线程没有执行完同步块之前,其它线程是无法访问其中的数据的.等到线程重新获得时间片,可以继续执行未执行完的代码.


问题在三到来:也许有人想到了,如果加了同步块,其它线程不能访问其中的内容,那要是GC线程呢?好吧,这我也不知道,等我知道了我再告诉你........


有知道的朋友希望可以解答~谢谢~
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值