我有以下代码:
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
的由弱引用中引用slaves
,并作为一个副作用消除了弱引用引用null
中slaves
。然后是一种依赖于每个slaves
参考成员的排序T
; 否则代码产生一个NullPointerException
。
由于unwrapped
在每个T
输入上都有一个引用slaves
,因此在排序过程中,没有GC会消除T
。最后,unwrapped = null
消除了对未包装的引用,因此再次释放了GC。似乎工作得很好。
如果我删除unwrapped = null;
此结果,则NullPointerExceptions
在某些负载下运行许多测试时会导致这种情况。我怀疑JIT消除了List<T> unwrapped = unwrap();
,因此GCT
在排序期间应用于从站中的。
您还有其他解释吗?如果您同意我的观点,这是JIT中的错误吗?
我个人认为这unwrapped = null
不是必需的,因为unwrapped
一旦updateOrdering()
返回就将其从框架中删除。有没有可以优化的规范,没有可以优化的规范?
还是我做错事了?我的想法是修改比较器,使其允许对进行弱引用null
。您对此有何看法?
感谢您的建议。
现在,我想补充一些缺少的信息:首先是Java版本:Java版本“ 1.7.0_45” OpenJDK运行时环境(IcedTea 2.4.3)(suse-8.28.3-x86_64)OpenJDK 64位服务器VM(内部版本) 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;
}
请注意,在进行迭代时,将删除无效引用。实际上,我用
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();
是一个重要的常数。
现在观察到,即使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进行排序。将无效弱引用放在列表的末尾,以后可以在此处收集。
我检查了您的源代码,当JIT编译与您的方法“ updateOrdering”相对应的方法时,我得到了NullPointerException,并且在排序期间发生了GC。
但是当Collections.sort无论有无包装= null时,我都收到NullPointerException。这可能发生在我的示例源代码与您的示例源代码之间的差异,或Java版本的差异。我将检查您是否告诉Java版本。
我使用低于版本的Java。
Java版本“ 1.7.0_40” Java(TM)SE运行时环境(内部版本1.7.0_40-b43) Java HotSpot(TM)64位服务器VM(内部版本24.0-b56,混合模式)
如果您想欺骗JIT编译,则以下代码插入您的源代码,而不是unwrapped = null(eg)。然后,JIT编译不会消除未包装的代码。
long value = unwrapped.size() * unwrapped.size();
if(value * value % 3 == 1) {
//Because value * value % 3 always is 1 or 0, this code can't reach.
//Insert into this the source code that use unwrapped array, for example, show unwrapped array.
}
我的考试结果如下。
因此,我(和您)建议JIT优化消除消除未包装的代码,然后发生NullPointerException。
顺便说一句,如果要显示JIT编译器优化,请使用-XX:+ PrintCompilation调用Java。
如果要显示GC,请使用-verbose:gc。
仅供参考,下面是我的示例源代码。
public class WeakSampleMain {
private static List<WeakReference<Integer>> weakList = new LinkedList<>();
private static long sum = 0;
public static void main(String[] args) {
System.out.println("start");
int size = 1_000_000;
for(int i = 0; i < size; i++) {
Integer value = Integer.valueOf(i);
weakList.add(new WeakReference<Integer>(value));
}
for(int i = 0; i < 10; i++) {
jitSort();
}
GcTask gcTask = new GcTask();
Thread thread = new Thread(gcTask);
thread.start();
for(int i = 0; i < 100000; i++) {
jitSort();
}
thread.interrupt();
System.out.println(sum);
}
public static void jitSort() {
List<Integer> unwrappedList = unwrapped();
removeNull();
Collections.sort(weakList,
new Comparator<WeakReference<Integer>>() {
@Override
public int compare(WeakReference<Integer> o1,
WeakReference<Integer> o2) {
return Integer.compare(o1.get(), o2.get());
}
}
);
for(int i = 0; i < Math.min(weakList.size(), 1000); i++) {
sum += weakList.get(i).get();
}
unwrappedList = null;
// long value = (sum + unwrappedList.size());
// if((value * value) % 3 == 2) {
// for(int i = 0; i < unwrappedList.size(); i++) {
// System.out.println(unwrappedList.get(i));
// }
// }
}
public static List<Integer> unwrapped() {
ArrayList<Integer> list = new ArrayList<Integer>();
for(WeakReference<Integer> ref : weakList) {
Integer i = ref.get();
if(i != null) {
list.add(i);
}
}
return list;
}
public static void removeNull() {
Iterator<WeakReference<Integer>> itr = weakList.iterator();
while(itr.hasNext()) {
WeakReference<Integer> ref = itr.next();
if(ref.get() == null) {
itr.remove();
}
}
}
public static class GcTask implements Runnable {
private volatile int result = 0;
private List<Integer> stockList = new ArrayList<Integer>();
public void run() {
while(true) {
if(Thread.interrupted()) {
break;
}
int size = 1000000;
stockList = new ArrayList<Integer>(size);
for(int i = 0; i < size; i++) {
stockList.add(new Integer(i));
}
if(System.currentTimeMillis() % 1000 == 0) {
System.out.println("size : " + stockList.size());
}
}
}
public int getResult() {
return result;
}
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句