我有以下代码:
private final List<WeakReference<T>> slaves;
public void updateOrdering() {
// removes void weak references
// and ensures that weak references are not voided
// during subsequent sort
List<T> unwrapped = unwrap();
assert unwrapped.size() == this.slaves.size();
// **** could be reimplemented without using unwrap() ****
Collections.sort(this.slaves, CMP_IDX_SLV);
unwrapped = null;// without this, ....
}
方法unwrap()
只是创建一个T
由 in 中的弱引用引用的 '列表,slaves
并且作为副作用消除了在 中的弱引用null
引用slaves
。然后是依赖于每个成员slaves
引用的排序T
;否则代码产生一个NullPointerException
.
由于在每个inunwrapped
上都有一个引用,因此在排序期间没有 GC 消除一个. 最后,消除 unwrapped 上的引用,从而再次释放 GC。似乎工作得很好。T
slaves
T
unwrapped = null
现在我的问题:
如果我在某些负载下运行许多测试时删除unwrapped = null;
此结果。NullPointerExceptions
我怀疑 JIT 消除了List<T> unwrapped = unwrap();
,因此 GCT
在排序期间适用于从属中的 's。
你还有别的解释吗?如果您同意我的观点,这是 JIT 中的错误吗?
我个人认为unwrapped = null
应该没有必要,因为一返回unwrapped
就从框架中移除updateOrdering()
。是否有规范可以优化哪些不是?
还是我做错了事?我有想法修改比较器,它允许在null
. 你怎么看?
感谢您的建议。
添加 (1)
现在我想补充一些缺失的信息: 首先是 Java 版本:java 版本“1.7.0_45” OpenJDK Runtime Environment (IcedTea 2.4.3) (suse-8.28.3-x86_64) OpenJDK 64-Bit Server VM (build 24.45-b08,混合模式)
然后有人想看方法展开
private synchronized List<T> unwrap() {
List<T> res = new ArrayList<T>();
T cand;
WeakReference<T> slvRef;
Iterator<WeakReference<T>> iter = this.slaves.iterator();
while (iter.hasNext()) {
slvRef = iter.next();
cand = slvRef.get();
if (cand == null) {
iter.remove();
continue;
}
assert cand != null;
res.add(cand);
} // while (iter.hasNext())
return res;
}
请注意,在迭代时,将删除 void 引用。事实上我用这个方法代替了
private synchronized List<T> unwrap() {
List<T> res = new ArrayList<T>();
for (T cand : this) {
assert cand != null;
res.add(cand);
}
return res;
}
使用我自己的迭代器,但在功能上应该是一样的。
然后有人想要堆栈跟踪。这是其中的一部分。
java.lang.NullPointerException: null
at WeakSlaveCollection$IdxComparator.compare(WeakSlaveCollection.java:44)
at WeakSlaveCollection$IdxComparator.compare(WeakSlaveCollection.java:40)
at java.util.TimSort.countRunAndMakeAscending(TimSort.java:324)
at java.util.TimSort.sort(TimSort.java:189)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at java.util.Collections.sort(Collections.java:217)
at WeakSlaveCollection.updateOrdering(WeakSlaveCollection.java:183)
它指向比较器,与返回的行。
static class IdxComparator
implements Comparator<WeakReference<? extends XSlaveNumber>> {
public int compare(WeakReference<? extends XSlaveNumber> slv1,
WeakReference<? extends XSlaveNumber> slv2) {
return slv2.get().index()-slv1.get().index();
}
} // class IdxComparator
最后,
private final static IdxComparator CMP_IDX_SLV = new IdxComparator();
是一个重要的常数。
添加 (2)
现在观察到,即使 updateOrdering() 中存在“unwrapped = null”,也确实发生了 NPE。
如果在 jit 优化后没有严格的引用,弱引用可能会被 java 运行时删除。源代码似乎根本不重要。
我通过以下方式解决了这个问题:
public void updateOrdering() {
Collections.sort(this.slaves, CMP_IDX_SLV);
}
没有插入任何装饰以防止从属设备被垃圾收集,并且 CMP_IDX_SLV 中的比较器启用以处理对 null 的弱引用:
public int compare(WeakReference<? extends XSlaveNumber> slv1,
WeakReference<? extends XSlaveNumber> slv2) {
XSlaveNumber sSlv1 = slv1.get();
XSlaveNumber sSlv2 = slv2.get();
if (sSlv1 == null) {
return sSlv2 == null ? 0 : -1;
}
if (sSlv2 == null) {
return +1;
}
assert sSlv1 != null && sSlv2 != null;
return sSlv2.index()-sSlv1.index();
}
作为副作用,排序底层列表 List> slaves;将 void 弱引用放在列表的末尾,以后可以在那里收集。