JavaのEscape AnalysisでNoEscapeがGlobalEscapeになってしまうケースの検証
Java ™ HotSpot Virtual Machine Performance Enhancements
Escape analysis is supported and enabled by default in Java SE 6u23 and later.
ということで最近のJVMでは有効になっているEscape analysisですが、こんな記事を見つけました。
Richard Burnison - Escape Analysis & Stack Allocated Objects
NoEscapeについて説明しているくだりで
Important to note, however, is that objects requiring finalizer execution are considered GlobalEscape and will not be stack-bound.
という記述があり、ちょっと気になったので試してみました。
$ java -version java version "1.7.0_45" Java(TM) SE Runtime Environment (build 1.7.0_45-b18) Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
まずは普通に。
public class Main { void run() { int totalLen = 0; for (int i = 0; i < 100000000; i++) { String s = new String("hello"); totalLen += s.length(); } System.out.println(totalLen); } public static void main(String argv[]) { Main main = new Main(); main.run(); } }
- Escape analysis無し
$ java -Xms512M -Xmx512M -XX:+PrintGCDetails -verbose:gc -XX:-DoEscapeAnalysis Main [GC [PSYoungGen: 132096K->432K(153600K)] 132096K->440K(503296K), 0.0030680 secs] [Times: user=0.00 sys=0.01, real=0.01 secs] 50000000 Heap PSYoungGen total 153600K, used 111393K [0x00000007f5500000, 0x0000000800000000, 0x0000000800000000) eden space 132096K, 84% used [0x00000007f5500000,0x00000007fc15c698,0x00000007fd600000) from space 21504K, 2% used [0x00000007fd600000,0x00000007fd66c010,0x00000007feb00000) to space 21504K, 0% used [0x00000007feb00000,0x00000007feb00000,0x0000000800000000) ParOldGen total 349696K, used 8K [0x00000007dff80000, 0x00000007f5500000, 0x00000007f5500000) object space 349696K, 0% used [0x00000007dff80000,0x00000007dff82000,0x00000007f5500000) PSPermGen total 21504K, used 2554K [0x00000007dad80000, 0x00000007dc280000, 0x00000007dff80000) object space 21504K, 11% used [0x00000007dad80000,0x00000007daffebf8,0x00000007dc280000)
- Escape analysis有り
$ java -Xms512M -Xmx512M -XX:+PrintGCDetails -verbose:gc -XX:+DoEscapeAnalysis Main 50000000 Heap PSYoungGen total 153600K, used 5284K [0x00000007f5500000, 0x0000000800000000, 0x0000000800000000) eden space 132096K, 4% used [0x00000007f5500000,0x00000007f5a29028,0x00000007fd600000) from space 21504K, 0% used [0x00000007feb00000,0x00000007feb00000,0x0000000800000000) to space 21504K, 0% used [0x00000007fd600000,0x00000007fd600000,0x00000007feb00000) ParOldGen total 349696K, used 0K [0x00000007dff80000, 0x00000007f5500000, 0x00000007f5500000) object space 349696K, 0% used [0x00000007dff80000,0x00000007dff80000,0x00000007f5500000) PSPermGen total 21504K, used 2552K [0x00000007dad80000, 0x00000007dc280000, 0x00000007dff80000) object space 21504K, 11% used [0x00000007dad80000,0x00000007daffe060,0x00000007dc280000)
Escape analysis有りの場合、Eden領域の使用量が少なくHeapではなくStack allocationになっているものと推測。
では、finalize() 実装版
public class Main { static int finalizeCount = 0; void run() { int totalLen = 0; for (int i = 0; i < 10000000; i++) { String s = new String("hello"); totalLen += s.length(); } System.out.println(totalLen); System.out.println(finalizeCount); } @Override protected void finalize() throws Throwable { finalizeCount++; super.finalize(); } public static void main(String argv[]) { Main main = new Main(); main.run(); } }
これをEA有効にして実行してみると
$ java -Xms512M -Xmx512M -XX:+PrintGCDetails -verbose:gc -XX:+DoEscapeAnalysis Main 50000000 0 Heap PSYoungGen total 153600K, used 5284K [0x00000007f5500000, 0x0000000800000000, 0x0000000800000000) eden space 132096K, 4% used [0x00000007f5500000,0x00000007f5a29028,0x00000007fd600000) from space 21504K, 0% used [0x00000007feb00000,0x00000007feb00000,0x0000000800000000) to space 21504K, 0% used [0x00000007fd600000,0x00000007fd600000,0x00000007feb00000) ParOldGen total 349696K, used 0K [0x00000007dff80000, 0x00000007f5500000, 0x00000007f5500000) object space 349696K, 0% used [0x00000007dff80000,0x00000007dff80000,0x00000007f5500000) PSPermGen total 21504K, used 2552K [0x00000007dad80000, 0x00000007dc280000, 0x00000007dff80000) object space 21504K, 11% used [0x00000007dad80000,0x00000007daffe2f0,0x00000007dc280000)
と、finalize() 実装前と変わらないので、"objects requiring finalizer execution are considered GlobalEscape and will not be stack-bound" というのは(少なくとも1.7.0_45では)気にしなくて良さそうかなぁと思います。