java – JIT优化和弱引用
我有以下代码:
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()只是创建一个由Slaves中的弱引用引用的T列表 由于unwrapped在slave中的每个T上都有一个引用,因此在排序过程中没有GC消除T.最后,unwrapped = null消除了unwrapped上的引用 现在我的问题: 如果我删除unwrapped = null;在某些负载下运行许多测试时,这会导致NullPointerExceptions.我怀疑JIT消除了List< T> unwrapped = unwrap(); 你有其他解释吗?如果您同意我的意见,这是JIT中的错误吗? 我个人认为unwrapped = null不是必需的,因为一旦updateOrdering()返回,就会从帧中删除unwrapped.是否存在可以优化和不优化的规范? 或者我是以错误的方式做事了?我有想法修改比较器,它允许对null的弱引用.你觉得怎么样? 谢谢你的建议. 加入(1) 现在我想添加一些缺失的信息: 然后有人想看方法展开 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也会发生. java运行时可能会删除弱引用 我通过以下方式解决了问题: public void updateOrdering() { Collections.sort(this.slaves,CMP_IDX_SLV); } 没有插入任何装饰,以防止奴隶被垃圾收集 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>奴隶; 解决方法
我检查你的源代码,当JIT编译我的方法对应你的方法“updateOrdering”并且GC在排序期间发生时,我得到了NullPointerException.
但是当Collections.sort无论是否有unwrapped = null时,我都得到了NullPointerException. 我使用java下面的版本. java version "1.7.0_40" Java(TM) SE Runtime Environment (build 1.7.0_40-b43) Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56,mixed mode) 如果你想欺骗JIT编译,下面的代码插入你的源代码而不是unwrapped = null(例如).然后,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没有优化我对应于updateOrdering的方法,则不会发生NullPointerException. >如果JIT优化我的方法插入上面的代码欺骗JIT编译器,那么就不会发生NullPointerException. 所以,我(和你)建议JIT optimze消除未包装的代码,然后发生NullPointerException. 顺便说一下,如果要显示JIT编译器优化,可以使用-XX:PrintCompilation调用java. 仅供参考,我的示例源代码如下. 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; } } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |