使用Java 7进行逃逸分析/堆栈分配的资格 [英] Eligibility for escape analysis / stack allocation with Java 7

查看:179
本文介绍了使用Java 7进行逃逸分析/堆栈分配的资格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 escape analysis ,以便更好地理解哪些对象有资格进行堆栈分配。



以下是我编写的用于测试堆栈分配的代码:

  import java.util.ArrayList; 
import java.util.Iterator;


public class EscapeAnalysis {

private static final long TIME_TO_TEST = 10L * 1000L; // 10s

static class Timestamp {
private long millis;
public Timestamp(long millis){
this.millis = millis;
}
public long getTime(){
return millis;
}
public void setTime(long time){
millis = time;



public static void main(String [] args){
long r = 0;
System.out.println(test1);
r + = test1();
System.out.println(test2);
r + = test2();
System.out.println(test3);
r + = test3();
System.out.println(test4);
r + = test4();
System.out.println(test5);
r + = test5();
System.out.println(test6);
r + = test6();
System.out.println(r);
}

public static long test1(){
long r = 0;
long start = System.currentTimeMillis();
while(System.currentTimeMillis() - start< TIME_TO_TEST){
r + = new Timestamp(System.currentTimeMillis())。getTime();
}
return r;
}

public static long test2(){
ArrayList< Integer> l = new ArrayList< Integer>(1000);
for(int i = 0; i <1000; ++ i){
l.add(i);
}
long r = 0;
long start = System.currentTimeMillis(); (Iterator< Integer> it = l.iterator(); it.hasNext();){
r + =
while(System.currentTimeMillis() - start< TIME_TO_TEST) it.next()的longValue();
}
}
return r;
}

public static long test3(){
long r = 0;
long start = System.currentTimeMillis(); (System.currentTimeMillis() - start< TIME_TO_TEST){
Timestamp ts = new Timestamp(System.currentTimeMillis());
while(System.currentTimeMillis
ts.setTime(42);
r + = ts.getTime();
}
return r;
}

public static long test4(){
ArrayList< Integer> l = new ArrayList< Integer>(1000);
for(int i = 0; i <1000; ++ i){
l.add(i);
}
long r = 0;
long start = System.currentTimeMillis();
while(System.currentTimeMillis() - start< TIME_TO_TEST){
Iterator< Integer> it = l.iterator();
r + = it.next()。longValue();
r + = it.next()。longValue();
r + = it.next()。longValue();
r + = it.next()。longValue();
}
return r;
}

public static long test5(){
ArrayList< Integer> l = new ArrayList< Integer>(1000);
for(int i = 0; i <1000; ++ i){
l.add(i);
}
long r = 0;
long start = System.currentTimeMillis();
while(System.currentTimeMillis() - start< TIME_TO_TEST){
Iterator< Integer> it = l.iterator();
for(int i = 0; i< l.size(); ++ i){
r + = it.next()。longValue();
}
}
return r;
}

public static long test6(){
long r = 0;
long start = System.currentTimeMillis(); (Timestamp ts = new Timestamp(System.currentTimeMillis());
ts.getTime()> 0;
while(System.currentTimeMillis() - start< TIME_TO_TEST){

ts.setTime(ts.getTime()+ System.currentTimeMillis())){
r + = ts.getTime();
}
}
return r;
}

}

以下是输出结果Linux上的Java 7

  java -server -version 
java版本1.7.0_02
Java TM)SE运行时环境(build 1.7.0_02-b13)
Java HotSpot™64位服务器虚拟机(构建22.0-b10,混合模式)

java -server -verbose: gc -XX:CompileThreshold = 1 -cp bin EscapeAnalysis
test1
test2
[GC 15616K-> 352K(59776K),0.0014270 secs]
[GC 15968K-> ; 288K(59776K),0,0011790秒]
[GC 15904K-> 288K(59776K),0.0018170秒]
[GC 15904K-> 288K(59776K),0.0011100秒]
[GC 15904K-> 288K(57152K),0.0019790秒]
[GC 15520K-> 320K(56896K),0.0011670秒]
[GC 15232K-> ; 284K(56256K),0,0011440秒]
test3
test4
test5
[GC 14876K-> 348K(55936K),0,0005340秒]
[GC14620K-> 348K(56000K),0,0004560秒]
[GC 14300K-> 316K(55296K),0004680秒]
[GC 13948K-> 316K(55488K),0.0003590秒]
[GC 13692K-> 316K(54784K),0004580秒]
[GC 13436K-> 316K(54976K ),0005430秒]
[GC 13180K-> 316K(54272K),0004500秒]
[GC 12924K-> 316K(54464K),0,0005090秒]
[GC12668K-> 316K(53760K),0.0004490秒]
[GC 12412K-> 316K(53888K),0.0004350秒]
[GC 12156K-> 316K(53312K ),0,0005060秒]
test6
6737499643744733086

我正在使用GC记录已知对象是否分配到堆栈(来自 Java中的转义分析的想法)不是100%可靠的,但似乎给出了很好的提示。



在输出上,对test1,test3,test4和test6的堆栈分配工作并且对test2不起作用和test5。我不明白为什么这对于for循环中的迭代器不起作用,尽管它可以工作




  • 循环(见test4),
  • 与for循环内的另一个对象(见test6)。


    我已阅读 ArrayList迭代器,我不明白为什么它不适合在测试2和5中进行堆栈分配,因为它既不会转义当前方法也不会转移当前线程。



    有什么想法?

    解决方案

    EA是C2编译器基于它产生的IR,因此您需要它在享受好处之前编译该方法。每个测试只被调用一次,所以没有机会编译。有关EA和C2 IR在热点内部wiki中的详细信息( https:/ /wikis.oracle.com/display/HotSpotInternals/Overview+of+Ideal,+C2 的+高+级+中级+表示和 https://wikis.oracle.com/display/HotSpotInternals/EscapeAnalysis

    这是一个版本尝试显示影响

      import com.sun.management.ThreadMXBean; 

    import java.lang.management.ManagementFactory;
    import java.util.ArrayList;
    import java.util.Iterator;


    public class EscapeAnalysisTest {

    private static final long TIME_TO_TEST = 10L * 1000L; // 10s

    static class Timestamp {
    private long millis;

    public Timestamp(long millis){
    this.millis = millis;
    }

    public long getTime(){
    return millis;
    }

    public void setTime(long time){
    millis = time;



    public static void main(String [] args){
    System.out.println(****);
    doIt();
    System.out.println(****);
    doIt();
    System.out.println(****);
    doIt();
    System.out.println(****);
    doIt();
    System.out.println(****);


    private static void doIt(){
    final ThreadMXBean mxbean =(ThreadMXBean)ManagementFactory.getThreadMXBean();
    final long tid = Thread.currentThread()。getId();
    long r = 0;
    final final allocPre = mxbean.getThreadAllocatedBytes(tid);
    r + = test1();
    long alloc1 = mxbean.getThreadAllocatedBytes(tid);
    System.out.println(test1 - +(alloc1 - allocPre));
    r + = test2();
    final long alloc2 = mxbean.getThreadAllocatedBytes(tid);
    System.out.println(test2 - +(alloc2 - alloc1));
    r + = test3();
    final long alloc3 = mxbean.getThreadAllocatedBytes(tid);
    System.out.println(test3 - +(alloc3 - alloc2));
    r + = test4();
    final long alloc4 = mxbean.getThreadAllocatedBytes(tid);
    System.out.println(test4 - +(alloc4 - alloc3));
    r + = test5();
    final long alloc5 = mxbean.getThreadAllocatedBytes(tid);
    System.out.println(test5 - +(alloc5 - alloc4));
    r + = test6();
    final long alloc6 = mxbean.getThreadAllocatedBytes(tid);
    System.out.println(test6 - +(alloc6 - alloc5));
    System.out.println(r);
    }

    public static long test1(){
    long r = 0;
    long start = System.currentTimeMillis();
    while(System.currentTimeMillis() - start< TIME_TO_TEST){
    r + = new Timestamp(System.currentTimeMillis())。getTime();
    }
    return r;
    }

    public static long test2(){
    ArrayList< Integer> l = new ArrayList< Integer>(1000);
    for(int i = 0; i <1000; ++ i){
    l.add(i);
    }
    long r = 0;
    long start = System.currentTimeMillis(); (Iterator< Integer> it = l.iterator(); it.hasNext();){
    r + =
    while(System.currentTimeMillis() - start< TIME_TO_TEST) it.next()的longValue();
    }
    }
    return r;
    }

    public static long test3(){
    long r = 0;
    long start = System.currentTimeMillis(); (System.currentTimeMillis() - start< TIME_TO_TEST){
    Timestamp ts = new Timestamp(System.currentTimeMillis());
    while(System.currentTimeMillis
    ts.setTime(42);
    r + = ts.getTime();
    }
    return r;
    }

    public static long test4(){
    ArrayList< Integer> l = new ArrayList< Integer>(1000);
    for(int i = 0; i <1000; ++ i){
    l.add(i);
    }
    long r = 0;
    long start = System.currentTimeMillis();
    while(System.currentTimeMillis() - start< TIME_TO_TEST){
    Iterator< Integer> it = l.iterator();
    r + = it.next()。longValue();
    r + = it.next()。longValue();
    r + = it.next()。longValue();
    r + = it.next()。longValue();
    }
    return r;
    }

    public static long test5(){
    ArrayList< Integer> l = new ArrayList< Integer>(1000);
    for(int i = 0; i <1000; ++ i){
    l.add(i);
    }
    long r = 0;
    long start = System.currentTimeMillis();
    while(System.currentTimeMillis() - start< TIME_TO_TEST){
    Iterator< Integer> it = l.iterator();
    for(int i = 0; i< l.size(); ++ i){
    r + = it.next()。longValue();
    }
    }
    return r;
    }

    public static long test6(){
    long r = 0;
    long start = System.currentTimeMillis(); ();
    while(System.currentTimeMillis() - start< TIME_TO_TEST){
    for(Timestamp ts = new Timestamp(System.currentTi());
    ts.getTime()> 0;
    ts.setTime(ts.getTime()+ System.currentTimeMillis())){
    r + = ts.getTime();
    }
    }
    return r;
    }

    }

    运行时会产生以下输出 -server -XX:CompileThreshold = 1

      **** 
    test1 - 109048
    test2 - 89243416
    test3 - 16664
    test4 - 42840
    test5 - 71982168
    test6 - 1400
    -5351026995119026839
    ****
    test1 - 16432
    test2 - 85921464
    test3 - 16664
    test4 - 42840
    test5 - 66777600
    test6 - 1368
    7844020592566674506
    ****
    test1 - 48
    test2 - 18256
    test3 - 272
    test4 - 18264
    test5 - 18264
    test6 - 272
    -2137858376905291730
    ****
    test1 - 48
    test2 - 18256
    test3 - 272
    test4 - 18264
    test5 - 18264
    test6 - 272
    3273987624143297143
    ****

    这里的一个危险是这个方法的编译已经从根本上改变了它,我没有试图防止这个,所以一些使用 LogCompilation PrintCompilation 可能需要检查。


    I am doing some tests with escape analysis in Java 7 in order to better understand what objects are eligible to stack allocation.

    Here is the code I wrote to test stack allocation:

    import java.util.ArrayList;
    import java.util.Iterator;
    
    
    public class EscapeAnalysis {
    
        private static final long TIME_TO_TEST = 10L * 1000L; // 10s
    
        static class Timestamp {
            private long millis;
            public Timestamp(long millis) {
                this.millis = millis;
            }
            public long getTime() {
                return millis;
            }
            public void setTime(long time) {
                millis = time;
            }
        }
    
        public static void main(String[] args) {
            long r = 0;
            System.out.println("test1");
            r += test1();
            System.out.println("test2");
            r += test2();
            System.out.println("test3");
            r += test3();
            System.out.println("test4");
            r += test4();
            System.out.println("test5");
            r += test5();
            System.out.println("test6");
            r += test6();
            System.out.println(r);
        }
    
        public static long test1() {
            long r = 0;
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < TIME_TO_TEST) {
                r += new Timestamp(System.currentTimeMillis()).getTime();
            }
            return r;
        }
    
        public static long test2() {
            ArrayList<Integer> l = new ArrayList<Integer>(1000);
            for (int i = 0; i < 1000; ++i) {
                l.add(i);
            }
            long r = 0;
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < TIME_TO_TEST) {
                for (Iterator<Integer> it = l.iterator(); it.hasNext(); ) {
                    r += it.next().longValue();
                }
            }
            return r;
        }
    
        public static long test3() {
            long r = 0;
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < TIME_TO_TEST) {
                Timestamp ts = new Timestamp(System.currentTimeMillis());
                ts.setTime(42);
                r += ts.getTime();
            }
            return r;
        }
    
        public static long test4() {
            ArrayList<Integer> l = new ArrayList<Integer>(1000);
            for (int i = 0; i < 1000; ++i) {
                l.add(i);
            }
            long r = 0;
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < TIME_TO_TEST) {
                Iterator<Integer> it = l.iterator();
                r += it.next().longValue();
                r += it.next().longValue();
                r += it.next().longValue();
                r += it.next().longValue();
            }
            return r;
        }
    
        public static long test5() {
            ArrayList<Integer> l = new ArrayList<Integer>(1000);
            for (int i = 0; i < 1000; ++i) {
                l.add(i);
            }
            long r = 0;
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < TIME_TO_TEST) {
                Iterator<Integer> it = l.iterator();
                for (int i = 0; i < l.size(); ++i) {
                    r += it.next().longValue();
                }
            }
            return r;
        }
    
        public static long test6() {
            long r = 0;
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < TIME_TO_TEST) {
                for (Timestamp ts = new Timestamp(System.currentTimeMillis());
                        ts.getTime() > 0;
                        ts.setTime(ts.getTime() + System.currentTimeMillis())) {
                    r += ts.getTime();
                }
            }
            return r;
        }
    
    }
    

    And here is what it outputs with Java 7 on Linux

    java -server -version                                                 
    java version "1.7.0_02"
    Java(TM) SE Runtime Environment (build 1.7.0_02-b13)
    Java HotSpot(TM) 64-Bit Server VM (build 22.0-b10, mixed mode)
    
    java -server -verbose:gc -XX:CompileThreshold=1 -cp bin EscapeAnalysis
    test1
    test2
    [GC 15616K->352K(59776K), 0,0014270 secs]
    [GC 15968K->288K(59776K), 0,0011790 secs]
    [GC 15904K->288K(59776K), 0,0018170 secs]
    [GC 15904K->288K(59776K), 0,0011100 secs]
    [GC 15904K->288K(57152K), 0,0019790 secs]
    [GC 15520K->320K(56896K), 0,0011670 secs]
    [GC 15232K->284K(56256K), 0,0011440 secs]
    test3
    test4
    test5
    [GC 14876K->348K(55936K), 0,0005340 secs]
    [GC 14620K->348K(56000K), 0,0004560 secs]
    [GC 14300K->316K(55296K), 0,0004680 secs]
    [GC 13948K->316K(55488K), 0,0003590 secs]
    [GC 13692K->316K(54784K), 0,0004580 secs]
    [GC 13436K->316K(54976K), 0,0005430 secs]
    [GC 13180K->316K(54272K), 0,0004500 secs]
    [GC 12924K->316K(54464K), 0,0005090 secs]
    [GC 12668K->316K(53760K), 0,0004490 secs]
    [GC 12412K->316K(53888K), 0,0004350 secs]
    [GC 12156K->316K(53312K), 0,0005060 secs]
    test6
    6737499643744733086
    

    I am using GC logs to known whether objects were allocated on the stack (idea from Escape analysis in Java) which might not be 100% reliable but seems to give good hints.

    Baed on the output, stack allocation works for test1, test3, test4 and test6 and doesn't work for test2 and test5. I don't understand why this doesn't work with an iterator in for-loop although it works

    • with an iterator outside a for-loop (see test4),
    • with another object inside a for-loop (see test6).

    I have read the code for the ArrayList iterator and I don't understand why it would not be eligible for stack allocation in tests 2 and 5 since it does neither escape the current method nor the current thread.

    Any idea?

    解决方案

    EA is something the C2 compiler analyses based on the IR it generates therefore you need it to compile the method before enjoying the benefits. Each test is called once only so there is no chance for it to compile. Details on EA and the C2 IR in the hotspot internals wiki (https://wikis.oracle.com/display/HotSpotInternals/Overview+of+Ideal,+C2's+high+level+intermediate+representation and https://wikis.oracle.com/display/HotSpotInternals/EscapeAnalysis)

    Here's a version that attempts to show the impact

    import com.sun.management.ThreadMXBean;
    
    import java.lang.management.ManagementFactory;
    import java.util.ArrayList;
    import java.util.Iterator;
    
    
    public class EscapeAnalysisTest {
    
        private static final long TIME_TO_TEST = 10L * 1000L; // 10s
    
        static class Timestamp {
            private long millis;
    
            public Timestamp(long millis) {
                this.millis = millis;
            }
    
            public long getTime() {
                return millis;
            }
    
            public void setTime(long time) {
                millis = time;
            }
        }
    
        public static void main(String[] args) {
            System.out.println("****");
            doIt();
            System.out.println("****");
            doIt();
            System.out.println("****");
            doIt();
            System.out.println("****");
            doIt();
            System.out.println("****");
        }
    
        private static void doIt() {
            final ThreadMXBean mxbean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
            final long tid = Thread.currentThread().getId();
            long r = 0;
            final long allocPre = mxbean.getThreadAllocatedBytes(tid);
            r += test1();
            long alloc1 = mxbean.getThreadAllocatedBytes(tid);
            System.out.println("test1 - " + (alloc1 - allocPre));
            r += test2();
            final long alloc2 = mxbean.getThreadAllocatedBytes(tid);
            System.out.println("test2 - " + (alloc2 - alloc1));
            r += test3();
            final long alloc3 = mxbean.getThreadAllocatedBytes(tid);
            System.out.println("test3 - " + (alloc3 - alloc2));
            r += test4();
            final long alloc4 = mxbean.getThreadAllocatedBytes(tid);
            System.out.println("test4 - " + (alloc4 - alloc3));
            r += test5();
            final long alloc5 = mxbean.getThreadAllocatedBytes(tid);
            System.out.println("test5 - " + (alloc5 - alloc4));
            r += test6();
            final long alloc6 = mxbean.getThreadAllocatedBytes(tid);
            System.out.println("test6 - " + (alloc6 - alloc5));
            System.out.println(r);
        }
    
        public static long test1() {
            long r = 0;
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < TIME_TO_TEST) {
                r += new Timestamp(System.currentTimeMillis()).getTime();
            }
            return r;
        }
    
        public static long test2() {
            ArrayList<Integer> l = new ArrayList<Integer>(1000);
            for (int i = 0; i < 1000; ++i) {
                l.add(i);
            }
            long r = 0;
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < TIME_TO_TEST) {
                for (Iterator<Integer> it = l.iterator(); it.hasNext(); ) {
                    r += it.next().longValue();
                }
            }
            return r;
        }
    
        public static long test3() {
            long r = 0;
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < TIME_TO_TEST) {
                Timestamp ts = new Timestamp(System.currentTimeMillis());
                ts.setTime(42);
                r += ts.getTime();
            }
            return r;
        }
    
        public static long test4() {
            ArrayList<Integer> l = new ArrayList<Integer>(1000);
            for (int i = 0; i < 1000; ++i) {
                l.add(i);
            }
            long r = 0;
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < TIME_TO_TEST) {
                Iterator<Integer> it = l.iterator();
                r += it.next().longValue();
                r += it.next().longValue();
                r += it.next().longValue();
                r += it.next().longValue();
            }
            return r;
        }
    
        public static long test5() {
            ArrayList<Integer> l = new ArrayList<Integer>(1000);
            for (int i = 0; i < 1000; ++i) {
                l.add(i);
            }
            long r = 0;
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < TIME_TO_TEST) {
                Iterator<Integer> it = l.iterator();
                for (int i = 0; i < l.size(); ++i) {
                    r += it.next().longValue();
                }
            }
            return r;
        }
    
        public static long test6() {
            long r = 0;
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < TIME_TO_TEST) {
                for (Timestamp ts = new Timestamp(System.currentTi());
                     ts.getTime() > 0;
                     ts.setTime(ts.getTime() + System.currentTimeMillis())) {
                    r += ts.getTime();
                }
            }
            return r;
        }
    
    }
    

    which generates the following output when run with -server -XX:CompileThreshold=1

    ****
    test1 - 109048
    test2 - 89243416
    test3 - 16664
    test4 - 42840
    test5 - 71982168
    test6 - 1400
    -5351026995119026839
    ****
    test1 - 16432
    test2 - 85921464
    test3 - 16664
    test4 - 42840
    test5 - 66777600
    test6 - 1368
    7844020592566674506
    ****
    test1 - 48
    test2 - 18256
    test3 - 272
    test4 - 18264
    test5 - 18264
    test6 - 272
    -2137858376905291730
    ****
    test1 - 48
    test2 - 18256
    test3 - 272
    test4 - 18264
    test5 - 18264
    test6 - 272
    3273987624143297143
    ****
    

    one danger here is that the compilation of this method has changed it more fundamentally, I haven't attempted to guard against this so some use of LogCompilation or PrintCompilation might be required to check.

    这篇关于使用Java 7进行逃逸分析/堆栈分配的资格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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