Java – JIT optimization and weak references

I have the following 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,....
}

The unwrap () method simply creates a t list referenced by weak references in slaves, and eliminates null weak references in dependencies as a side effect Then there is the sort that depends on each slave member referencing some T; Otherwise, the code will generate NullPointerException

Since unwrapped has a reference on each t in the slave, there is no GC to eliminate T. finally, unwrapped = null eliminates the reference on unwrapped, and then publishes GC again It seems to work well

Now my question:

If I delete unwrapped = null; This results in nullpointerexceptions when running many tests under some load I suspect that JIT eliminates list < T > unwrapped = unwrap(); Therefore, GC is applicable to t

Do you have any other explanation? If you agree with me, is this an error in JIT?

Personally, I don't think unwrapped = null is necessary, because once updateordering () returns, unwrapped will be deleted from the frame Are there specifications that can be optimized and not optimized?

Or did I do things the wrong way? I have an idea to modify the comparator, which allows weak references to null How did you like it?

Thank you for your advice

Join (1)

Now I want to add some missing information: first, the 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 (built-in 24.45-b08, mixed mode)

Then someone wants to see how it unfolds

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 the void reference will be removed during the iteration In fact, I replaced it with this method

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

return res;
}

I use my own iterator, but it should be functionally the same

Then someone lingers in the stack trace This is a piece

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 to the comparator and returns the line

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

last,

private final static IdxComparator CMP_IDX_SLV = new IdxComparator();

Is an important constant

Join (2)

Now observe that NPE occurs even if 'unwrapped = null' exists in updateordering()

The Java runtime may delete weak references if there are no strict references after JIT optimization The source code doesn't seem to matter

I solved the problem in the following ways:

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

No decorations were inserted to prevent slaves from being garbage collected and enable CMP_ IDX_ The comparator in SLV handles 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, order the basic list > slave; Place the void weak reference at the end of the list where you can collect it later

Solution

I check your source code. When JIT compiles my method corresponding to your method "updateordering" and GC occurs during sorting, I get NullPointerException

But when collections Sort whether unwrapped = null or not, I get NullPointerException This may occur between my sample source code and your sample source code, or Java version differences I'll check if you tell the Java version

I use the following version of 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)

If you want to cheat JIT compilation, insert the following code into your source code instead of unwrapped = null (for example) Then, JIT compilation does not eliminate 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 test scores are as follows

>If the JIT does not optimize my method corresponding to updateordering, NullPointerException. > If JIT optimizes my method, NullPointerException will occur at some time

>If the JIT optimizer inserts the above code into my method to deceive the JIT compiler, NullPointerException will not occur

Therefore, I (and you) suggest that JIT Optimze eliminate the unpacked code, and then NullPointerException occurs

By the way, if you want to display JIT compiler optimizations, you can use - XX: printcompilation to call Java If you want to display GC, use - verbose: GC

For reference only, my sample source code is as follows

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;
        }
    }
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>