java的可维护性包括_关于java:弱参考可维护性

我正在阅读Java中的弱引用,听起来很简单,如果对象上只有弱引用,那么垃圾回收器可以收集它。 除非您的引用在使用该值之前失效,该怎么办?

例:

假设我有一个键为{1,2,3,4,5}的弱哈希图,它们的值均为1。现在假设您有一个随机数生成器,用于[1:10]中的数字。 现在,每次获取数字时,它都会检查它是否在地图中为键,然后为该键提供临时的强引用。 因此,使用此设置,您将拥有一些具有强引用的键,从而保留在内存中,但同时也有一些键在被选择之前会失效的可能性。

如果我对弱哈希图的直觉是正确的,这是否意味着该映射将在某个时候从其原始状态更改?

尝试将Integer对象用作WeakHashMap的键可能会导致某些奇怪的行为。首先,WeakHashMap的javadoc具有以下注释:

This class is intended primarily for use with key objects whose equals methods test for object identity using the == operator. Once such a key is discarded it can never be recreated, so it is impossible to do a lookup of that key in a WeakHashMap at some later time and be surprised that its entry has been removed. This class will work perfectly well with key objects whose equals methods are not based upon object identity, such as String instances. With such recreatable key objects, however, the automatic removal of WeakHashMap entries whose keys have been discarded may prove to be confusing.

考虑以下代码:

WeakHashMap map = new WeakHashMap<>();

Integer k = Integer.valueOf(9001);

map.put(k,"OVER 9000!?");

while (true)

{

System.out.println(map.get(k));

Thread.sleep(100);

k = Integer.valueOf(9001);

System.gc();

}

循环将通过打印" OVER 9000 !?"开始,但是在第一个循环之后,原始密钥已被丢弃(即使现在已经引用了equals的密钥)。结果,如果该关键对象被垃圾回收,则该条目将从映射中删除,并且循环将开始打印" null"。由于我们在丢弃密钥后调用了System.gc();,因此很可能在单个循环之后发生。

但是,使用Integer作为WeakHashMap键的问题还没有结束。如果将9001以上的值更改为1,您会发现行为发生了变化! (可能吗?这可能取决于实现。)现在,该条目永远不会从映射中删除。这是因为整数缓存-Integer.valueOf(1)总是返回相同的Integer实例,但是Integer.valueOf(9001)每次都会创建一个新的Integer实例。

第二个问题特定于Integer,但第一个问题实际上适用于您尝试使用equals并非基于==的键的任何方案。如果equals是基于==的,那么您的问题就不会真正适用-如果您不再对键有很强的引用,则该值是否从映射中删除也无关紧要,因为您将无法再使用它-您无法重新创建使用基于身份的相等性的密钥。

帖子的重点不应处理您正在回答的问题。我想知道在一定时间内无法获取密钥是否会导致在我有机会使用密钥之前将其删除。

最后一段对此进行了讨论。如果您能够以一致的方式获取密钥,那么一定已经有人对其进行了强有力的引用,这是一个有争议的问题(只要您的密钥使用基于身份的等同性)。

对于以下情况,弱引用也很重要:在这种情况下,您授予某人访问某个键的权限(通过为他们分配一个对其分配了强引用的堆栈),并且当堆栈关闭时(由他们完成),则缺少强引用会使收集它成为公平的游戏?

强引用不仅仅来自堆栈。例如,它们也可以在堆上。不过,您所说的其余部分通常是正确的-我通常看到WeakHashMap用于缓存元数据或有关用作其键的对象的计算数据。当无法再访问那些对象时(例如,因为使用它们的代码已经完成),则不再需要该元数据,并且可以在这些对象被垃圾回收的同时被自动丢弃。

这个答案已经解决了由于在行为取决于对象身份(如可达性)的构造中使用基于值的相等性类型而引起的问题。

简而言之,当您能够构造与无法访问的按键相同的新对象时,就有可能检测到按键的突然移除。

但是,您也可以将弱可及对象转回强可及状态,例如通过调用WeakReference的get()方法或遍历WeakHashMap的映射时。

WeakHashMap map = new WeakHashMap<>();

Object key = new Object();

map.put(key, true);

WeakReference ref = new WeakReference<>(key);

key = null;

// now, the key object is only weakly reachable

key = ref.get();

// now, the key object might be strongly reachable again

// in that case, this statement will print true

System.out.println(map.get(key));

具有唯一标识且没有通过new Object()覆盖的equals方法的对象的构造确保不会存在对同一对象的其他引用或相等的对象。在此代码的某一点上,该对象仅是弱可及的,但随后很可能将其变为强可及的。

这些点之间可能会发生垃圾回收,并且由于原子地清除了对对象的所有弱引用,因此可以通过从get()获取null引用来检测这种情况。但是,此时垃圾收集发生的可能性非常低。因此,链接的答案之间使用了对System.gc()的调用,以提高弱引用被清除的可能性。

这是一个人为的示例,但有助于解决您的问题,"……这是否意味着地图将在某个时候从其原始状态改变?"。

如果您使用具有不同标识的相等密钥或在一段时间内很难访问的密钥,则地图可能会在某个时间更改,但无法保证会发生这种情况。这取决于垃圾收集器何时运行并实际发现某些对象的弱可达性。但是通常,JVM会尝试阻止垃圾收集,直到真正需要垃圾收集为止。因此,应用程序可能会安静运行一段时间而根本不进行垃圾收集。此外,如果您确实定期轮询映射,则可能甚至会发生,因为gc在查找过程中可以很好地访问密钥的时间点正确运行。

WeakReference的目的是帮助进行内存管理。如您所写,"如果对象没有被正常使用"(没有强引用,实际上是持有它的直接变量),"那么您就不再需要它"(可以将其垃圾回收)。如果哈希映射较弱,则它取决于密钥,因此通常将其用于缓存临时关联的数据。

话虽如此,仅将某些内容放入弱哈希图中而不继续使用该键作为强引用是没有意义的,因为收集器可以在访问它之前立即收集它。

可能不会(即使System.gc()也不强制GC运行),但是您不能依靠它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值