簡體   English   中英

為什么getSum不會被熱點jvm內聯?

[英]Why getSum does not get inlined by hotspot jvm?

這是我嘗試從Java Performance中重現的示例關於轉義分析 的權威指南,第97頁 這可能是應該發生的情況:

  1. getSum()必須變得足夠熱,並且必須使用適當的JVM參數將其內聯到調用程序main()
  2. 由於listsum變量都不會從main()方法中轉義,因此可以將它們標記為NoEscape因此JVM可以為它們使用堆棧分配,而不是堆分配。

但是我通過jitwatch運行了它,結果表明getSum()編譯為本機程序集,而沒有內聯到main() 因此,更不用說堆棧分配也沒有發生。

我在這里做錯了什么? (我將整個代碼和熱點日志放在這里 。)

這是代碼:

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.stream.IntStream;

public class EscapeAnalysisTest {

    private static class Sum {

        private BigInteger sum;
        private int n;

        Sum(int n) {
            this.n = n;
        }

        synchronized final BigInteger getSum() {
            if (sum == null) {
                sum = BigInteger.ZERO;
                for (int i = 0; i < n; i++) {
                    sum = sum.add(BigInteger.valueOf(i));
                }
            }
            return sum;
        }

    }

    public static void main(String[] args) {
        ArrayList<BigInteger> list = new ArrayList<>();
        for (int i = 1; i < 1000; i++) {
            Sum sum = new Sum(i);
            list.add(sum.getSum());
        }
        System.out.println(list.get(list.size() - 1));
    }

}

我使用的JVM參數:

-server
-verbose:gc
-XX:+UnlockDiagnosticVMOptions
-XX:+TraceClassLoading
-XX:MaxInlineSize=60
-XX:+PrintAssembly
-XX:+LogCompilation

為了知道為什么要內聯某些東西,可以在編譯日志中查找inline_successinline_fail標記。

但是,即使要獲得內聯的東西,也必須對調用方進行編譯,在您的情況下,您希望在main方法中進行內聯,因此,唯一的方式是堆棧替換(OSR)。 看你的日志,你可以看到幾個OSR編譯但沒有的main方法:根本就不是你足夠的工作main方法。

您可以通過增加for循環的迭代次數來解決此問題。 通過將其增加到100_000 ,我得到了第一個OSR編譯。

對於這樣一個小例子, -XX:+PrintCompilation -XX:+PrintInlining而不是整個LogCompilation輸出,我看到了:

@ 27   EscapeAnalysisTest$Sum::getSum (51 bytes)   inlining prohibited by policy

這不是很有幫助...但是,通過查看HotSpot源代碼可以發現,這可能是由於阻止C1編譯為由C2進行OSR編譯的內聯方法的策略所致。 無論如何,查看C1編譯完成的內聯並不是一件有趣的事情。

添加更多的循環迭代次數( 1_000_000 ,對Sum進行參數模1_000_000以減少運行時間)將獲得main的C2 OSR,其內容為:

@31   EscapeAnalysisTest$Sum::getSum (51 bytes)   already compiled into a big method  

C2的策略的那部分是自描述性的,並且由InlineSmallCode標志控制: -XX:InlineSmallCode=4k告訴HotSpot“大方法”的閾值是本機代碼的4kB。 在我的機器上足以使getSum內聯:

  14206   45 %     4       EscapeAnalysisTest::main @ 10 (61 bytes)
                              @ 25   EscapeAnalysisTest$Sum::<init> (10 bytes)   inline (hot)
                                @ 1   java.lang.Object::<init> (1 bytes)   inline (hot)
              s               @ 31   EscapeAnalysisTest$Sum::getSum (51 bytes)   inline (hot)
                                @ 31   java.math.BigInteger::valueOf (62 bytes)   inline (hot)
                                  @ 58   java.math.BigInteger::<init> (77 bytes)   inline (hot)
                                    @ 1   java.lang.Number::<init> (5 bytes)   inline (hot)
                                      @ 1   java.lang.Object::<init> (1 bytes)   inline (hot)
                                @ 34   java.math.BigInteger::add (123 bytes)   inline (hot)
                                  @ 41   java.math.BigInteger::add (215 bytes)   inline (hot)
                                  @ 48   java.math.BigInteger::<init> (38 bytes)   inline (hot)
                                    @ 1   java.lang.Number::<init> (5 bytes)   inline (hot)
                                      @ 1   java.lang.Object::<init> (1 bytes)   inline (hot)
                              @ 34   java.util.ArrayList::add (29 bytes)   inline (hot)
                                @ 7   java.util.ArrayList::ensureCapacityInternal (13 bytes)   inline (hot)
                                  @ 6   java.util.ArrayList::calculateCapacity (16 bytes)   inline (hot)
                                  @ 9   java.util.ArrayList::ensureExplicitCapacity (26 bytes)   inline (hot)
                                    @ 22   java.util.ArrayList::grow (45 bytes)   too big

(請注意,我從未使用過MaxInlineSize

作為參考,下面是修改后的循環:

for (int i = 1; i < 1_000_000; i++) {
  Sum sum = new Sum(i % 10_000);
  list.add(sum.getSum());
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM