Java中的转义分析

发布于 2024-07-17 16:13:47 字数 313 浏览 10 评论 0原文

据我所知,JVM 使用转义分析来进行某些性能优化比如锁粗化和锁省略。 我感兴趣的是 JVM 是否有可能决定可以使用逃逸分析在堆栈上分配任何特定对象。

一些资源让我认为我是对的。 是否有 JVM 能够真正做到这一点?

As far as I know the JVM uses escape analysis for some performance optimisations like lock coarsening and lock elision.
I'm interested if there is a possibility for the JVM to decide that any particular object can be allocated on stack using escape analysis.

Some resources make me think that I am right. Is there JVMs that actually do it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

溇涏 2024-07-24 16:13:47

使用此版本的 java -XX:+DoEscapeAnalysis 可以大大减少 gc 活动,并且执行速度提高 14 倍。

$ java -version
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
    Java HotSpot(TM) Client VM (build 14.0-b16, mixed mode, sharing)

$ uname -a
Linux xxx 2.6.18-4-686 #1 SMP Mon Mar 26 17:17:36 UTC 2007 i686 GNU/Linux

没有逃逸分析,

$ java -server -verbose:gc EscapeAnalysis|cat -n
     1  start
     2  [GC 896K->102K(5056K), 0.0053480 secs]
     3  [GC 998K->102K(5056K), 0.0012930 secs]
     4  [GC 998K->102K(5056K), 0.0006930 secs]
   --snip--
   174  [GC 998K->102K(5056K), 0.0001960 secs]
   175  [GC 998K->102K(5056K), 0.0002150 secs]
   176  10000000

有逃逸分析,

$ java -server -verbose:gc -XX:+DoEscapeAnalysis EscapeAnalysis
start
[GC 896K->102K(5056K), 0.0055600 secs]
10000000

有逃逸分析执行时间显着减少。 为此,循环更改为 10e9 次迭代,

public static void main(String [] args){
    System.out.println("start");
    for(int i = 0; i < 1000*1000*1000; ++i){
        Foo foo = new Foo();
    }
    System.out.println(Foo.counter);
}

没有逃逸分析,

$ time java -server EscapeAnalysis
start
1000000000

real    0m27.386s
user    0m24.950s
sys     0m1.076s

有逃逸分析,

$ time java -server -XX:+DoEscapeAnalysis EscapeAnalysis
start
1000000000

real    0m2.018s
user    0m2.004s
sys     0m0.012s

因此,在有逃逸分析的情况下,示例的运行速度比非逃逸分析的运行速度快约 14 倍。

With this version of java -XX:+DoEscapeAnalysis results in far less gc activity and 14x faster execution.

$ java -version
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
    Java HotSpot(TM) Client VM (build 14.0-b16, mixed mode, sharing)

$ uname -a
Linux xxx 2.6.18-4-686 #1 SMP Mon Mar 26 17:17:36 UTC 2007 i686 GNU/Linux

Without escape analysis,

$ java -server -verbose:gc EscapeAnalysis|cat -n
     1  start
     2  [GC 896K->102K(5056K), 0.0053480 secs]
     3  [GC 998K->102K(5056K), 0.0012930 secs]
     4  [GC 998K->102K(5056K), 0.0006930 secs]
   --snip--
   174  [GC 998K->102K(5056K), 0.0001960 secs]
   175  [GC 998K->102K(5056K), 0.0002150 secs]
   176  10000000

With escape analysis,

$ java -server -verbose:gc -XX:+DoEscapeAnalysis EscapeAnalysis
start
[GC 896K->102K(5056K), 0.0055600 secs]
10000000

The execution time reduces significantly with escape analysis. For this the loop was changed to 10e9 iterations,

public static void main(String [] args){
    System.out.println("start");
    for(int i = 0; i < 1000*1000*1000; ++i){
        Foo foo = new Foo();
    }
    System.out.println(Foo.counter);
}

Without escape analysis,

$ time java -server EscapeAnalysis
start
1000000000

real    0m27.386s
user    0m24.950s
sys     0m1.076s

With escape analysis,

$ time java -server -XX:+DoEscapeAnalysis EscapeAnalysis
start
1000000000

real    0m2.018s
user    0m2.004s
sys     0m0.012s

So with escape analysis the example ran about 14x faster than the non-escape analysis run.

美羊羊 2024-07-24 16:13:47

我不认为它会对堆栈分配进行转义分析。 示例:

public class EscapeAnalysis {

    private static class Foo {
        private int x;
        private static int counter;

        public Foo() {
            x = (++counter);
        }
    }
    public static void main(String[] args) {
        System.out.println("start");
        for (int i = 0; i < 10000000; ++i) {
            Foo foo = new Foo();
        }

        System.out.println(Foo.counter);
    }
}

使用 -server -verbose:gc -XX+DoEscapeAnalysis

start
[GC 3072K->285K(32640K), 0.0065187 secs]
[GC 3357K->285K(35712K), 0.0053043 secs]
[GC 6429K->301K(35712K), 0.0030797 secs]
[GC 6445K->285K(41856K), 0.0033648 secs]
[GC 12573K->285K(41856K), 0.0050432 secs]
[GC 12573K->301K(53952K), 0.0043682 secs]
[GC 24877K->277K(53952K), 0.0031890 secs]
[GC 24853K->277K(78528K), 0.0005293 secs]
[GC 49365K->277K(78592K), 0.0006699 secs]
10000000

据称 JDK 7 支持堆栈分配

I don't think it does escape analysis for stack allocation. example:

public class EscapeAnalysis {

    private static class Foo {
        private int x;
        private static int counter;

        public Foo() {
            x = (++counter);
        }
    }
    public static void main(String[] args) {
        System.out.println("start");
        for (int i = 0; i < 10000000; ++i) {
            Foo foo = new Foo();
        }

        System.out.println(Foo.counter);
    }
}

with -server -verbose:gc -XX+DoEscapeAnalysis:

start
[GC 3072K->285K(32640K), 0.0065187 secs]
[GC 3357K->285K(35712K), 0.0053043 secs]
[GC 6429K->301K(35712K), 0.0030797 secs]
[GC 6445K->285K(41856K), 0.0033648 secs]
[GC 12573K->285K(41856K), 0.0050432 secs]
[GC 12573K->301K(53952K), 0.0043682 secs]
[GC 24877K->277K(53952K), 0.0031890 secs]
[GC 24853K->277K(78528K), 0.0005293 secs]
[GC 49365K->277K(78592K), 0.0006699 secs]
10000000

Allegedly JDK 7 supports stack allocation.

彼岸花ソ最美的依靠 2024-07-24 16:13:47

越狱分析确实不错,但这并不是完全获得越狱卡。 如果对象内部有一个动态大小的集合,则逃逸分析不会从堆切换到堆栈。 例如:

public class toEscape {
   public long l;
   public List<Long> longList = new ArrayList<Long>();
}

即使这个对象是在方法中创建的,并且从语法的角度来看绝对不会转义,编译器也不会将其标记为转义。 我怀疑是因为从纯粹的语法角度来看, longList 的大小并没有真正限制,它可能会破坏你的堆栈。 因此我认为这个案子需要通过。 我对此进行了实验,其中 longList 为空,但它仍然在一个简单的微基准测试中引起了集合。

Escape analysis is really nice, but it is not a complete get of jail free card. if you have a dynamically sized collection inside of an object, the escape analysis will NOT switch from heap to stack. For example:

public class toEscape {
   public long l;
   public List<Long> longList = new ArrayList<Long>();
}

Even if this object is created in a method and absolutely does NOT escape from a syntactic point of view, the compiler will not mark this for escape. I suspect because that longList is not really bounded in size from a pure syntactic perspective and it could blow your stack potentially. Thus I believe it takes a pass on this case. I experimented with this where the longList was empty and still it caused collections in a simple micro benchmark.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文