JIT优化和弱引用 [英] JIT Optimization and Weak References

查看:180
本文介绍了JIT优化和弱引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下一段代码:

  private final List< WeakReference< T>>奴隶; 

public void updateOrdering(){
//删除void弱引用
//并确保弱引用不会被无效
//在随后的排序过程中
列出< T> unwrapped = unwrap();
assert unwrapped.size()== this.slaves.size();
// ****可以在不使用unwrap()的情况下重新实现()****
Collections.sort(this.slaves,CMP_IDX_SLV);
unwrapped = null; //没有这个,....
}

方法 unwrap()只是创建 T 列表中的从属
,并且作为副作用消除了在从属 null 的弱引用C>。
然后依赖于 slaves 的每个成员引用一些 T ;
,否则代码产生一个 NullPointerException



由于 unwrapped 在排序过程中,在从属中的每个 T 中都有一个引用,否则GC将消除Ť。最后, unwrapped = null 消除了解包
的引用,因此再次释放GC。似乎工作得很好。



现在我的问题是:



如果我删除 unwrapped = null; 在一些负载下运行多个测试时,会导致 NullPointerExceptions 。我怀疑JIT消除了 List< T> unwrapped = unwrap();
,所以GC在排序时应用于从站中的 T


你有另外的解释吗?如果你同意我的意见,这是JIT中的一个错误吗?



我个人认为 unwrapped = null 应该不是必需的,因为 updateOrdering()返回时,框架中的 unwrapped 会从框架中移除。有什么规格可以优化,什么不是?

或者我是否以错误的方式做事?我有想法修改比较器,它允许 null 上的弱引用。你对此有何看法?



感谢您的建议。

Add on(1)



现在我想添加一些缺失的信息:
首先是Java版本:
java版本1.7.0_45
OpenJDK运行时环境(IcedTea 2.4.3)(suse-8.28.3-x86_64)
OpenJDK 64位服务器虚拟机构建24.45-b08,混合模式)

然后有人想看到解包的方法

 私人同步列表< 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();
继续;
}
assert cand!= null;
res.add(cand);
} // while(iter.hasNext())

return res;
}

请注意,迭代时,void引用将被删除。
实际上,我用

 私有同步列表< T> unwrap(){
List< T> res = new ArrayList< T>();
for(T cand:this){
assert cand!= null;
res.add(cand);
}

return res;
}

使用我自己的迭代器,但功能上它应该是相同的。

然后有人逃离栈跟踪。这是它的一部分。

  java.lang.NullPointerException:null在$ WeakSlaveCollection 
$ IdxComparator.compare(WeakSlaveCollection.java:44)$ b $ WeakSlaveCollection $ IdxComparator.compare(WeakSlaveCollection.java:40)
在java.util.TimSort.countRunAndMakeAscending(TimSort.java:324)
在java.util.TimSort.sort(TimSort.java :189)java.util.TimSort.sort中的
(TimSort.java:173)java.util.Arrays.sort处的
(Arrays.java:659)java.util中的
。 Collections.sort(Collections.java:217)
WeakSlaveCollection.updateOrdering(WeakSlaveCollection.java:183)

它指向比较器,与返回行。

 静态类IdxComparator 
实现比较器< WeakReference<扩展了XSlaveNumber>> {
public int compare(WeakReference< ;? extends XSlaveNumber> slv1,
WeakReference< ;? extends XSlaveNumber> slv2){
return slv2.get()。index() - slv1.get() 。指数();

} // class IdxComparator

最后,

  private final static IdxComparator CMP_IDX_SLV = new IdxComparator(); 

是一个重要的常数。

Add on(2)



现在观察到即使存在'unwrapped = null'也会出现NPE在updateOrdering()中。
$ b 如果没有严格的引用在jit优化之后持有 ,那么弱引用可能会被java运行时
删除。
源代码似乎并不重要。



我通过以下方式解决了问题:

  public void updateOrdering (){
Collections.sort(this.slaves,CMP_IDX_SLV);
}

没有插入任何装饰以防止奴隶被垃圾收集
和CMP_IDX_SLV中的比较器能够处理对null的弱引用:

  public int compare(WeakReference< ;? extends XSlaveNumber> slv1,
WeakReference< ;?扩展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使用或不使用unwrapped = null时,我得到NullPointerException。
这可能会导致我的示例源代码和您的示例源代码之间的差异,或Java版本差异。我会检查你是否告诉Java版本。



我使用java以下版本。


<$ p $
Java版本1.7.0_40
Java™SE运行时环境(build 1.7.0_40-b43)
Java HotSpot™64位服务器虚拟机(版本24.0- b56,混合模式)

如果您想在JIT编译中作弊,下面的代码会插入您的源代码,而不是unwrapped = null(例如) 。然后,JIT编译不会消除未包装的代码。

  long value = unwrapped.size()* unwrapped.size(); 
if(value * value%3 == 1){
//因为value * value%3总是为1或0,所以这段代码无法到达。
//在此插入使用解包数组的源代码,例如show unwrapped array。
}

我的检查结果如下。




  • 如果JIT不优化与updateOrdering相对应的方法,则不会发生NullPointerException。
  • 如果JIT优化了我的方法,那么NullPointerException在某个时候发生。

  • 如果JIT优化我的方法插入上述源代码作弊JIT编译器,则不会发生NullPointerException。


    $ b因此,我(和你)建议JIT优化消除了解包的代码,然后发生NullPointerException。

    p>顺便说一句,如果你想显示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>(); (WeakReference< Integer> ref:weakList){
    Integer i = ref.get();
    if(i!= null){
    list.add(i);
    }
    }
    返回列表;
    }

    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;
    私人列表<整数> 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;
    }
    }
    }


    I have the following piece of code:

    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, ....
    }
    

    Method unwrap() just creates a list of T's referenced by the weak references in slaves and as a side effect eliminates the weak references referencing null in slaves. Then comes the sort which relies on that each member of slaves references some T; otherwise the code yields a NullPointerException.

    Since unwrapped holds a reference on each T in slaves, during sorting no GC eliminates a T. Finally, unwrapped = null eliminates the reference on unwrapped and so releases GC again. Seems to work quite well.

    Now my question:

    If I remove unwrapped = null; this results in NullPointerExceptions when running many tests under some load. I suspect that the JIT eliminates List<T> unwrapped = unwrap(); and so GC applies to the T's in slaves during sorting.

    Do you have another explanation? If you agree with me, is this a bug in the JIT?

    I personally think that unwrapped = null should not be necessary, because unwrapped is removed from the frame as soon as updateOrdering() returns. Is there a specification what may be optimized and what is not?

    Or did I do the thing in the wrong way? I have the idea to modify comparator that it allows weak references on null. What do you think about that?

    Thanks for suggestions.

    Add on (1)

    Now I want to add some missing pieces of information: First of all Java version: java version "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, mixed mode)

    Then someone wanted to see method unwrap

    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;
    }
    

    Note that while iterating, void references are removed. In fact i replaced this method by

    private synchronized List<T> unwrap() {
    List<T> res = new ArrayList<T>();
    for (T cand : this) {
        assert cand != null;
        res.add(cand);
    }
    
    return res;
    }
    

    using my own iterator but functionally this should be the same.

    Then someone wantet the stacktrace. Here is a piece of it.

     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)
    

    it points into the comparator, the line with the return.

    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 
    

    and finally,

     private final static IdxComparator CMP_IDX_SLV = new IdxComparator();
    

    is an important constant.

    Add on (2)

    Observed now that indeed NPE occurs even if 'unwrapped = null' is present in updateOrdering().

    Weak references may be removed by java runtime if no strict reference holds after jit optimization. The source code seems not important at all.

    I solved the problem the following way:

    public void updateOrdering() {
    Collections.sort(this.slaves, CMP_IDX_SLV);
    }
    

    without any decoration inserted to prevent slaves to be garbage collected and the comparator in CMP_IDX_SLV enabled to handle weak references to 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();
        }
    

    As a side effect, ordering the underlying list List> slaves; puts the void weak references at the end of the list, where it can be collected later.

    解决方案

    I examine your source code, and I got NullPointerException when JIT compile my method corresponding to your method "updateOrdering" and GC occurs during sorting.

    But I got NullPointerException when Collections.sort whether with or without unwrapped = null. This maybe occurs difference between my sample source code and yours, or Java version difference. I will examine if you tell Java version.

    I use java below version.

    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)
    

    If you want to cheat on JIT compilation, the below code insert your source code instead unwrapped = null(e.g.). Then, JIT compilation doesn't eliminates unwrapped code.

    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.
    }
    

    My examination result is below.

    • If JIT don't optimize my method corresponding to updateOrdering, no NullPointerException occurs.
    • If JIT optimize my method, then NullPointerException occurs at some point.
    • If JIT optimize my method inserting the above source code cheating JIT compiler, then no NullPointerException occurs.

    So, I(and you) suggest JIT optimze eliminates unwrapped code, then NullPointerException occurs.

    By the way, if you want to show JIT compiler optimization, you invoke java with -XX:+PrintCompilation.
    If you want to show GC, with -verbose:gc.

    Just for information, my sample source code is below.

    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;
            }
        }
    }
    

    这篇关于JIT优化和弱引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆