ã¹ã¿ãã¯ãã¬ãŒã¹ãšããããã³ãã«ã€ããŠç¥ãããããšãã¹ãŠã ããŒã1
以äžã¯ã
JUGã® 1ã€ã§ããOdnoklassnikiã®
apanginãšããŠç¥ãããAndrey
Panginã«ããã¬ããŒãã®ãã³ãŒãã®ç¬¬2éšã§ãïŒJPoint 2016ããã®åœŒã®ã¬ããŒãã®ããããšæ¡åŒµããŒãžã§ã³ïŒã ä»åã¯ãã¹ã¿ãã¯ãã¬ãŒã¹ã«ã€ããŠã®äŒè©±ãçµäºãããã³ããã³ããšããããã³ãã«ã€ããŠã説æããŸãã
ããã§ã¯ãç¶ããŸããã...

ååž°ã«ã€ããŠè©±ãå§ããã®ã§ã決ããŠè¿ããªããããªååž°çãªã¡ãœãããå®è¡ãããšã©ããªããŸããã
static int depth; static void recursion() { depth++; recursion(); } public static void main(String[] args) { recursion(); }
StackOverflowErrorã衚瀺ããããŸã§ã«ãæšæºã®ã¹ã¿ãã¯ãµã€ãºã§äœåã®åŒã³åºããæž¡ãããŸããïŒ
枬å®ããŠã¿ãŸãããïŒ
package demo4; public class Recursion { static int depth; static void recursion() { depth++; recursion(); } public static void main(String[] args) { try { recursion(); } catch (StackOverflowError e) { System.out.println(depth); } } }
åãã³ãŒãã§ããã£ããStackOverflowErrorãè¿œå ããŸããã
ã¹ã¿ãã¯ãµã€ãºã1 MBã®64ãããã·ã¹ãã ã§ã¯ãçµæã¯22ãã35ååã®åŒã³åºãã«ãªããŸãã ãªããããªã«å€§ããªéããããã®ã§ããïŒ ãã€ã³ãã¯JITã§ããã¡ãœããã¯ãJavaã³ãŒãã®å®è¡ãšäžŠè¡ããŠãã³ã³ãã€ã©ã®ããã¯ã°ã©ãŠã³ãã¹ããªãŒã ã§ã³ã³ãã€ã«ãããŸãã ããæç¹ã§ïŒååž°ã¡ãœããããã§ã«æ°ååŒã³åºãããåŸïŒããã®ã¡ãœããã®ã³ã³ãã€ã«ãéå§ããããã®æç¹ã§ã€ã³ã¿ãŒããªã¿ãŒã§ã®å®è¡ãç¶è¡ãããŸãã ã³ã³ãã€ã©ãäœæ¥ãå®äºãããšããã«ã次ã®åŒã³åºãã¯ã³ã³ãã€ã«ãããã³ãŒãã«å
¥ããŸãã
Java 8以éãããã©ã«ãã§ã¯ã1ã€ã®VMã«2ã€ã®ã³ã³ãã€ã©ãŒããããŸã-ã軜ããC1ãšãéããC2 ã¹ã¿ãã¯äžã«3ã€ã®ã¿ã€ãã®ãã¬ãŒã ãããå Žåãç¶æ³ã¯å¯èœã§ãïŒè§£éæžã¿ãã³ã³ãã€ã«æžã¿C1ãããã³ã³ã³ãã€ã«æžã¿C2ã ãã¬ãŒã ãµã€ãºã¯å€§ããç°ãªãå ŽåããããŸãã ã€ã³ã¿ããªã¿ã«ã¯æãæ±ãã«ãããã¬ãŒã ããããŸããããã¯ããã¹ãŠãã¹ã¿ãã¯ã«æ ŒçŽãããããã§ãïŒãã¹ãŠã®åŒæ°ãããŒã«ã«å€æ°ãçŸåšã®ãã€ãã³ãŒããã€ã³ã¿ãŒãªã©ïŒã ããã®å€ãã¯ã³ã³ãã€ã«ãããã³ãŒãã«ã¯å¿
èŠãããŸãããã³ã³ãã€ã©ãŒãæé©ã§ããã»ã©ãã¹ã¿ãã¯ã«æ ŒçŽããå¿
èŠãå°ãªããªããŸãã ããšãã°ãC2ã¯ããŒã«ã«å€æ°ãã¹ã¿ãã¯äžã«é
眮ããŸããããã¹ãŠãã¬ãžã¹ã¿ã«ããã·ã¥ãã1ã¬ãã«äžã«ãªã³ã¯ããŸãã

ããŒã䜿çšããŠçŽç²ã«è§£éãããã¢ãŒãã§åãã³ãŒããå®è¡ãããå Žå
-Xint
çµæã¯ã»ãšãã©åžžã«12,500ïŒÂ±æ°ãã¬ãŒã ïŒã§ãã
ä»ã¯åãããšã§ãããC1ã³ã³ãã€ã©ã®åŸã§ãã
-Xcomp -XX:TieredStopAtLevel=1
C1ã³ã³ãã€ã©ã®å Žåãçµæãéåžžã«å®å®ããŠãããçŽ2äž5000ã§ãã
C2ã§ãã¹ãŠãäžåºŠã«ã³ã³ãã€ã«ããå ŽåïŒ
-Xcomp -XX:-TieredCompilation
ããã¯ãã¹ãŠé·ããªããŸãããçµæã¯62,000ãã¬ãŒã ã§ãã
æšæºã¹ã¿ãã¯ãµã€ãºïŒ1 MBïŒã62,000ã§å²ããšããã¬ãŒã ããšã«çŽ16ãã€ããæ¶è²»ãããããšãããããŸãã ã³ã³ãã€ã«ãããã³ãŒãã§ç¢ºèªããŸãã-ããã§ãã ãã¬ãŒã ãµã€ãºã¯å®éã«ã¯16ãã€ãã§ã¯ãªã32ãã€ãã§ããã1ãã¬ãŒã ã§ã¯2ã¬ãã«ã®ãã¹ããçŽæ¥æ¥ç¶ãããŠããŸãã

ããã©ã«ãã§ã¯ã64ãããã¢ãŒããã¯ãã£ã§ã¯ãã¹ã¿ãã¯ãµã€ãºã¯1 MBã§ããã調æŽå¯èœã§ãã ããã2ã€ã®ããŒã¯å矩èªã§ãã
-Xss, -XX:ThreadStackSize
ããŸãç¥ãããŠããªãäºå®ã¯ãç¹å®ã®ã¹ã¬ããã®ã¹ã¿ãã¯ãµã€ãºãå€æŽã§ããããšã§ãã
Thread(ThreadGroup, target, name, stackSize)
ãããã倧ããªã¹ã¿ãã¯ãäœæããå Žåãã¡ã¢ãªå
ã®å Žæãå æããããšãå¿ããŠã¯ãªããŸããããŸããã¹ã¿ãã¯ãµã€ãºã倧ããå€ãã®ã¹ã¬ãããã¡ã¢ãªäžè¶³ã«ã€ãªãããããªç¶æ³ãçºçããå¯èœæ§ããããŸãã
java.lang.OutOfMemoryError: Unable to create new native thread
èå³æ·±ãäºå®ïŒjvm
-XX:+PrintFlagsFinal
ãLinuxã§èŠããšã1 MBã®ThreadStackSizeããããWindowsãèŠããšãThreadStackSizeããŒã®ããã©ã«ãå€ã¯0ã«ãªããŸãã1Mbã¯ã©ãããæ¥ãŸããïŒ
ã¹ã¿ãã¯ã®ããã©ã«ããµã€ãºãexe-shnikã§æå®ãããŠããïŒã¢ããªã±ãŒã·ã§ã³ã®ããã©ã«ããµã€ãºãexe-formatã®å±æ§ã§æå®ãããŠããïŒããšã¯ãç§ã«ãšã£ãŠå瀺ã§ããã
64ãããã·ã¹ãã ã®æå°ã¹ã¿ãã¯ãµã€ãºã¯çŽ228 Kbã§ãïŒJDKã®ããŒãžã§ã³ã«ãã£ãŠç°ãªãå ŽåããããŸãïŒã ã¹ã¿ãã¯ã¯ã©ã®ããã«é
眮ããããã®æå°ãµã€ãºã¯ã©ãããæ¥ãŸããïŒ

ã¹ã¿ãã¯ã«ã¯ãJavaã¡ãœããã®ãã¬ãŒã ã«å ããŠããŸã ããã€ãã®äºçŽã¹ããŒã¹ããããŸãã ããã¯ãåžžã«ã¹ã¿ãã¯ã®æäžéšã«å°ãªããšã1ã€ã®ã¬ãããŸãŒã³ïŒ1ããŒãž-4 Kbã®ãµã€ãºïŒãšã€ãšããŒãŸãŒã³ã®ããã€ãã®ããŒãžã§ãã
ã¹ã¿ãã¯ãªãŒããŒãããŒããã§ãã¯ããã«ã¯ãã¬ãããŸãŒã³ãšã€ãšããŒãŸãŒã³ãå¿
èŠã§ãã æåã¯ãäž¡æ¹ã®ãŸãŒã³ãæžã蟌ã¿ä¿è·ãããŠããŸãã åJavaã¡ãœããã¯ãçŸåšã®ã¹ã¿ãã¯ãã€ã³ã¿ãŒã®ã¢ãã¬ã¹ãžã®æžã蟌ã¿ãè©Šè¡ããŠãã¬ãããŸãŒã³ãŸãã¯ã€ãšããŒãŸãŒã³ããã§ãã¯ããŸãïŒæžã蟌ã¿ãè©Šã¿ããšããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã¯ãä»®æ³ãã·ã³ããã£ããããŠåŠçããäŸå€ãçæããŸãïŒã é»è²ã®ãŸãŒã³ã«å°éãããšãã¹ã¿ãã¯ãªãŒããŒãããŒãã³ãã©ãŒãéå§ããã®ã«ååãªã¹ããŒã¹ã確ä¿ãããããã«ããã¯ã解é€ãããStackOverflowErrorã®ã€ã³ã¹ã¿ã³ã¹ãäœæããŠæž¡ãç¹å¥ãªã¡ãœããã«å¶åŸ¡ãæž¡ãããŸãã ã¬ãããŸãŒã³ã«å
¥ããšãå埩äžèœãªãšã©ãŒãçºçããä»®æ³ãã·ã³ã¯èŽåœçã«çµäºããŸãã
ããããã·ã£ããŠãŸãŒã³ããããŸãã ããªãå¥åŠãªãµã€ãºããããŸããWindowsã§ã¯6ããŒãžãLinuxãSolarisããã®ä»ã®ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã§ã¯20ããŒãžã§ãã ãã®ã¹ããŒã¹ã¯ãJDKå
ã®ãã€ãã£ãã¡ãœãããšä»®æ³ãã·ã³èªäœã®ããŒãºã®ããã«äºçŽãããŠããŸãã
ãã¬ãŒã³ããŒã·ã§ã³ã®æºåãããŠãããšãã«ãJava 8ãšJava 9ã®äž¡æ¹ã§ååž°ãã¹ã¿ãŒãèµ·åããŸãããã€ãã«ãä»®æ³ãã·ã³ïŒåºåãã©ã°ã¡ã³ãïŒã®ãã°ãããã¯ã©ãã·ã¥ãçºçããŸããã
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x0000019507acb5e0, pid=9048, tid=10544
#
# JRE version: Java(TM) SE Runtime Environment (9.0+119) (build 9-ea+119)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (9-ea+119, mixed mode, tiered, compressed oops, g1 gc, windows-amd64)
# Problematic frame:
# J 155 C2 demo4.Recursion.recursion()V (12 bytes) @ 0x0000019507acb5e0 [0x0000019507acb5e0+0x0000000000000000]
#
# No core dump will be written. Minidumps are not enabled by default on client versions of Windows
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
...
åœç¶ãå©çšå¯èœãªææ°ã®ãã«ããããŠã³ããŒãããŸããïŒã¬ããŒãã®æç¹ã§ã¯9.0 + 119ã§ããïŒããã®åé¡ãåçŸãããŠããŸãã
ããã¯ãã¯ã©ãã·ã¥ãã³ãåæã®éåžžã«è¯ãã±ãŒã¹ã§ãïŒAndrey Pangin-
JVMã¯ã©ãã·ã¥ãã³ãã®åæ ïŒã ããã§ã¯ããã¹ãŠã®ã¹ãã«ãç¹ã«å解ã圹ç«ã¡ãŸããã
以äžã¯ãçŸåšã®ã¹ã¿ãã¯ãã€ã³ã¿ãŒãåºæºã«ããŠå€ãæžã蟌ãåœä»€ã§ãã ãã®åœä»€ã§ã¯ã©ãã·ã¥ãçºçããŸããïŒ
Instructions:
00000000: 89 84 24 00 a0 ff ff mov DWORD PTR [rsp-0x6000],eax
00000007: 55 push rbp
00000008: 48 83 ec 10 sub rsp,0x10
0000000c: 49 ba 78 71 88 8d 00 00 00 00 movabs r10,0x8d887178
00000016: 41 83 42 70 02 add DWORD PTR [r10+0x70],0x2
0000001b: e8 e0 ff ff ff call 0x00000000
Registers:
RSP=0x0000007632e00ff8
Java Threads:
=>0x0000019571d71800 JavaThread "main" [_thread_in_Java, id=10544,
stack(0x0000007632e00000,0x0000007632f00000)]
0x0000007632e00ff8
RSPã¬ãžã¹ã¿ã®å€ã䜿çšããŠãæžã蟌ãã¢ãã¬ã¹ãèšç®ã§ããŸãã ãã®ã¢ãã¬ã¹ãã16é²æ°ã§6000ãæžç®ããå¿
èŠããããŸããäœããã®å€ãååŸããŸãã

ãã®å€ã§èšé²ããŸãã ã¯ã©ãã·ã¥ãã³ãã«ã¯ãçŸåšã®ã¹ã¬ããã®ã¹ã¿ãã¯ç¯å²ã衚瀺ãããŸãã

ãã®å€ã¯ããã®ã¹ã¿ãã¯ã®äžçªæåïŒæäžéšïŒã®ããŒãžã®çµãããã€ãŸã ã¬ãããŸãŒã³ã ãã§ãã
å®éããã®ãããªãã°ããããŸãã ç§ã¯ãããåæããçç±ãèŠã€ããŸããïŒäžéšã®JVMé¢æ°ã¯ãWindowsã§äœ¿çšå¯èœãª6ã€ã®ã·ã£ããŠããŒãžãæ¬ ããŠããŸãïŒå®è¡æã«å€ããå æããŸãïŒã ä»®æ³ãã·ã³ã®éçºè
ã誀ã£ãŠèšç®ããŸããã
ãšããã§ããããã®ãŸãŒã³ã®ãµã€ãºã¯JVMããŒã§å€æŽã§ããŸãã
ãªãããã°ã¹ã¿ãã¯ãå¿
èŠãªã®ã§ããïŒ Java EEã®å Žåãããã§ãªãå Žåã
ããã¯ããã®ããŒãã«é¢ããç§ã®ãæ°ã«å
¥ãã®åçã®1ã€ã§ãã

ããžãã¹ããžãã¯ã®2ã€ã®ã©ã€ã³ã¯ãããŸããŸãªãã¬ãŒã ã¯ãŒã¯ãšã¢ããªã±ãŒã·ã§ã³ãµãŒããŒããæ°çŸã®ãã¬ãŒã ãçæããŸãã
ããã©ãŒãã³ã¹æž¬å®ã¹ã¿ãã¯
ãããã¡ã€ãªã³ã°ã¯ãã·ã¹ãã ã®ããã©ãŒãã³ã¹ã枬å®ããããã®éèŠãªéšåã§ãã ãã¹ãŠã®ãããã¡ã€ã©ãŒã¯ããµã³ããªã³ã°ãšèšæž¬ã®2ã€ã®å€§ããªã°ã«ãŒãã«åããããšãã§ããŸãã
èšè£
ãããã¡ã€ã©ãŒã¯ãã¡ãœããã«åçŽã«ããŒã¯ãä»ããŸããã¡ãœããã®éå§æãšçµäºæã«ã¡ãœãããžã®å
¥ãå£ã«é¢ããã·ã°ãã«ãè¿œå ããŸããã¡ãœããããã®åºå£ã«é¢ããã·ã°ãã«ãè¿œå ããŸãã ãã®æ¹æ³ã§åã¡ãœãããæ瀺ãããšã枬å®ã¯éåžžã«æ£ç¢ºã«ãªããŸãããããã«ãã倧ããªãªãŒããŒããããçºçããããšã¯æããã§ãã
public void someMethod(String... args) { Profiler.onMethodEnter("myClass.someMethod");
å®çšŒåç°å¢ã§ã¯ããµã³ããªã³ã°ãããã¡ã€ã©ãŒãšããå¥ã®ã¢ãããŒããæããã䜿çšãããŸãã äžå®ã®åšæïŒ1ç§ããã10ã100åïŒã§ãããŒã®ãã³ããååŸãããã¬ãŒã¹ãçŸåšå®è¡ãããŠããã¹ã¬ããã調ã¹ãŸãã ãããã®ã¹ã¿ãã¯ãã¬ãŒã¹ã«æãé »ç¹ã«è©²åœããã¡ãœããã¯ãããã§ãã
ãããã©ã®ããã«æ©èœãããã®äŸãèŠãŠã¿ãŸãããã ç§ã¯å°ããªããã°ã©ã ãæžããŸããã ããã¯å°ãããšããäºå®ã«ãããããããããªãã¯ããã«ãããæžéããããšãã§ãããšèšãããšã¯ã§ããŸããã
ãŸãã2ã€ã®ã©ã³ãã ãªå°ç座æšãçæããŸãã 次ã«ããµã€ã¯ã«ã§ãã©ã³ãã ã«çæããã座æšããå¥ã®ç¹å®ã®ãã€ã³ãïŒã¢ã¹ã¯ã¯ïŒãŸã§ã®è·é¢ãèšç®ããŸãã å€æ°ã®æ°åŠãããdistanceToé¢æ°ããããŸãã
çµæã¯ããã·ã¥ãããã«è¿œå ãããŸãã
ã«ãŒãå
ã®ããã¯ãã¹ãŠãäœåºŠãäœåºŠãå®è¡ãããŸãã
package demo5; import java.util.IdentityHashMap; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; public class Location { static final double R = 6371009; double lat; double lng; public Location(double lat, double lng) { this.lat = lat; this.lng = lng; } public static Location random() { double lat = ThreadLocalRandom.current().nextDouble() * 30 + 40; double lng = ThreadLocalRandom.current().nextDouble() * 100 + 35; return new Location(lat, lng); } private static double toRadians(double x) { return x * Math.PI / 180; } public double distanceTo(Location other) { double dlat = toRadians(other.lat - this.lat); double dlng = toRadians(other.lng - this.lng); double mlat = toRadians((this.lat + other.lat) / 2); return R * Math.sqrt(Math.pow(dlat, 2) + Math.pow(Math.cos(mlat) * dlng, 2)); } private static Map<Location, Double> calcDistances(Location target) { Map<Location, Double> distances = new IdentityHashMap<>(); for (int i = 0; i < 100; i++) { Location location = Location.random(); distances.put(location, location.distanceTo(target)); } return distances; } public static void main(String[] args) throws Exception { Location moscow = new Location(55.755773, 37.617761); for (int i = 0; i < 10000000; i++) { calcDistances(moscow); } } }
ããã§ã¯ããã¹ãŠãé
ããªãå¯èœæ§ããããŸãïŒã©ã³ãã ãªåº§æšã®çæãè·é¢ã®æž¬å®ïŒå€ãã®æ°åŠããããŸãïŒãããã³ãããäžã®ã¬ã€ã¢ãŠãã®äž¡æ¹ã ãããã¡ã€ã©ãŒãå®è¡ããŠãæ£ç¢ºã«æéãããã£ãŠãããã®ãèŠãŠã¿ãŸãããã
Java VisualVMïŒæšæºã®JDKããã±ãŒãžã«å«ãŸããŠããŸã-ããç°¡åãªãã®ã¯ãããŸããïŒã䜿çšããSamplerã¿ãã§ããã»ã¹ãèŠã€ããCPUãã¯ãªãã¯ããŠæž¬å®ãéå§ããŸãïŒ30åéåäœãããŸãïŒã ããã©ã«ãã®æž¬å®ééã¯100ããªç§ããšã«1åã§ãã
äœãèµ·ãã£ãïŒ

ïŒJava VisualVMãããã¡ã€ã©ãŒã«ããã°ïŒå°ãå®å
šã§ã¯ãããŸããããIdentiryHashMap.putã«æéãè²»ãããŠããŸãã
SelfTimeã§ãœãŒããããæ¹æ³ã§å¹³æ¿ãèŠããšïŒ

ä»ã«äœããããŠããªããã®ããã«ã
åãããšã¯ãä»ã®ãããã¡ã€ã©ãŒïŒJProfilerãYourKitãªã©ïŒã§ã枬å®ã§ããŸããçµæã¯åãã«ãªããŸãã
HashMapã¯éåžžã«ãã¬ãŒããããã£ãŠããŸããïŒ ãã ãããã¡ã€ã©ãŒã ããåãã€ãã
åæã«ããããã¯åãæ¹æ³ã§é
眮ãããŸããæå®ãããé »åºŠã§ããã¹ãŠã®ã¹ã¬ããã®ãã³ããåãåãJMXãŸãã¯JVMTIãä»ããŠã¡ãœãããåŒã³åºããŸãã ããšãã°ãJVMTIã«ã¯
GetAllStackTracesã¡ãœããããããŸãã ä»®æ³ãã·ã³ã®èšãããšã¯ãããã§ãŸãšããŠå°å·ããŸãã
å®ã¯ããããã¯ãããã¡ã€ã©ãŒã§ã¯ãªããJVMã§ããã誀ã£ãã¹ã¿ãã¯ãã¬ãŒã¹ãæäŸããŸãã ãã¹ãŠã®ãããã¡ã€ã©ãŒã«ã¯1ã€ã®å€§ããªåé¡ããããŸããã¹ã¬ããã®ã¹ã¿ãã¯ãã¬ãŒã¹ã¯ãå®å
šãªæç¹ã§ã®ã¿åé€ã§ããŸãããããã¯ãä»®æ³ãã·ã³ãã¹ã¬ãããå®å
šã«åæ¢ã§ããããšãèªèããã³ãŒãã®ç¹å®ã®ãã€ã³ãã§ãã ãããŠãå®éã«ã¯ãã®ãããªãã€ã³ãã¯ã»ãšãã©ãããŸããããããã¯ã«ãŒãã®å
åŽã«ãããã¡ãœããã®åºå£ãã€ã³ãã«ãããŸãã ã³ãŒãã®å€§ããªãã£ã³ãã¹ãããå Žå-åãæ°åŠ; ãµã€ã¯ã«ãªã-ã»ãŒããã€ã³ãããŸã£ãããªãå ŽåããããŸããã€ãŸãããã®ãã£ã³ãã¹ã¯ã¹ã¿ãã¯ãã¬ãŒã¹ã«å°éããŸããã
å¥ã®åé¡ã¯ãã¹ãªãŒãäžã®ã¹ã¬ãããšå®è¡äžã®ã¹ã¬ãããåãæ¹æ³ã§ãµã³ããªã³ã°ãããããšã§ãã ãã¹ãŠã®ã¹ã¬ãããããã³ãããã³ãããŸãã ããã¯ããŸãè¯ããããŸãã ã¹ã¿ãã¯ãã¬ãŒã¹ã§ã¹ã¬ãããã¹ãªãŒãç¶æ
ã«ããå¿
èŠã¯ãããŸããã
ãŸããã»ãšãã©ã®ãããã¡ã€ã©ãŒã¯ãããçš®ã®ããããã³ã°ã·ã¹ãã ã³ãŒã«ã§ã¹ãªãŒããããã€ãã£ãã¡ãœãããåºå¥ã§ããŸããã ããšãã°ããœã±ããããã®ããŒã¿ãåŸ
æ©ããŠããå Žåãã¹ããªãŒã ã¯RUNNABLEç¶æ
ã«ãªãããããã¡ã€ã©ãŒã¯ã¹ããªãŒã ãCPUã100ïŒ
æ¶è²»ããŠããããšã瀺ããŸãã ãããã圌ã¯CPUãæ¶è²»ããŸãããä»®æ³ãã·ã³ã ãããåäœäžã®ãã€ãã£ãã¡ãœãããšããããã³ã°ã·ã¹ãã ã³ãŒã«ãåºå¥ã§ããŸããã
ã©ããã
OSã¯ããã€ãã£ãã³ãŒãã®ãããã¡ã€ãªã³ã°æ©èœãæäŸããŸãã Linuxã«ã€ããŠè©±ããšãã¿ã€ããŒãèšå®ããç¹å®ã®åšæ³¢æ°ã§ãããã¡ã€ãªã³ã°ããããã®ç¹å¥ãªOSã·ã°ãã«ïŒSIGPROFïŒãçæãã
setittimerã·ã¹ãã ã³ãŒã«ããããŸãã çŸåšå®è¡äžã®ã¹ã¬ããããããåãåããŸãã OSã®æ©èœãšSIGPROFã·ã°ãã«ãã³ãã©ãŒã䜿çšããŠãçŸåšã®ã¹ããªãŒã ã®ã¹ã¿ãã¯ãã¬ãŒã¹ãå®å
šãªå Žæã«ãªããŠãåéã§ãããšäŸ¿å©ã§ãã ãŸããHotSpotä»®æ³ãã·ã³ã§ã¯ããã®ãããªæ©äŒãæäŸãããŸãã ææžåãããŠããªããã©ã€ããŒãAPIããããŸãïŒAsyncGetCallTraceã¯ãã»ãŒããã€ã³ãã«ãªãçŸåšã®ã¹ã¬ããã¹ã¿ãã¯ãååŸããããã«åŒã³åºãããšãã§ããŸãã
ãã®ç©Žã¯ãç¹ã«Oracle Developer Studioã§èŠãããŸããã ããã¯ã»ãšãã©æ£çŽãªã¹ã¿ãã¯ãã¬ãŒã¹ãååŸãããããã¡ã€ã©ãŒã§ãã
ãã®ã¬ããŒãã®æºåäžã«ããããã®æ¹æ³ã䜿çšããä»ã®äººããããã©ãããç£èŠããŸããã æåéã2ã€ã®ãããžã§ã¯ããèŠã€ãããŸããã1ã€ã¯å€ããã®ã§æ¢ã«æŸæ£ããããããžã§ã¯ãã§ããã1ã€ã¯æ¯èŒçæè¿ïŒ2015幎ïŒç»å Žããæ£çŽãããã¡ã€ã©ãŒãšåŒã°ããŠããŸãã
ããã®APIã¯éåžžã«åçŽã§ããã¹ã¿ãã¯ãã¹ã¿ãã¯ããå Žæãæºåããã¡ãœãããåŒã³åºããŸãã

ãã®ã¡ãœããã®3çªç®ã®ãã©ã¡ãŒã¿ãŒã¯ãã·ã°ãã«ãã³ãã©ãŒã§ååŸãããçŸåšã®ã³ã³ããã¹ãã§ãã
ç§èªèº«ã®ãªãŒãã³ãœãŒã¹ãããã¡ã€ã©ãŒãžã®ãªã³ã¯ïŒ
https :
//github.com/apangin/async-profiler ãããåã-ããã䜿çšããŸãã çŸåšã圌ã¯ãã§ã«äººã
ãèŠããããšãæ¥ããŠããªãç¶æ
ã«ãããŸãã 確ãã«ãçŸåšã¯Linuxã®ã¿ã«å®è£
ãããŠããŸãïŒæ³šïŒã¬ããŒãããmacOSãµããŒããè¿œå ãããŠããŸãïŒã
åãäŸã確èªããŸãããã
ãããã¡ã€ãªã³ã°ããããã»ã¹ãèšããŸãã

pidã¯3202ã§ãã
ç§ã®ãããã¡ã€ã©ãŒïŒãããŸã§èŠãããšã®ãªãïŒã®æ©èœã¯ããªã³ã¶ãã©ã€ã§æ¥ç¶ã§ããããšã§ãïŒèšåãããŠããæ£çŽãªãããã¡ã€ã©ãŒã¯ãã¢ããªã±ãŒã·ã§ã³ã®èµ·åæã«JavaãšãŒãžã§ã³ããšããŠå®è¡ããå¿
èŠããããŸãïŒã
ãããã¡ã€ãªã³ã°ã«æ°ç§ãäžããŸãããã çµæãšããŠåŸããããã®ã¯æ¬¡ã®ãšããã§ãã

æåŸã«ãã¡ãœããã®ãã©ãããªã¹ãããããŸãã ãããã«é«ã-åå¥ã®è©³çŽ°ïŒã¹ã¬ããã®ãã¹ãŠã®ã¹ã¿ãã¯ïŒã ç¶æ³ã¯æ ¹æ¬çã«ç°ãªããŸãã ãã¹ãŠã®æéã®ã»ãŒ3åã®1ãæ°åŠã«è²»ããããŠããŸã-è·é¢ã®èšç®ã§ãã IdentityHashMap.put-éåžžã¯äžéšã«ãããçµæã¯2ïŒ
ã§ãïŒæåã®ãããã¡ã€ã©ãŒã«ãããšã100ïŒ
ãå ããŠããŸãïŒã ãããããªããžã§ã¯ãã®identityHashCodeã®èšç®ã«ã¯æ¬åœã«æéãããããŸãã ãããŠãããããšãªãµã€ãºèªäœã«å€ãã®æéãè²»ããããŸãã ã¡ãªã¿ã«ãã©ã³ãã ãªå Žæã®çæãç¡æã§ã¯ãããŸããïŒå°ãªããšã12ïŒ
ïŒã
éããæããŠãã ããã
ãã®ãããã¡ã€ã©ãŒã®ãªãŒããŒãããã¯ã¯ããã«å°ãªãã§ãã 1ç§éã«å°ãªããšã1000åèµ·åã§ããŸãããã¢ã¯ãã£ããªã¹ã¬ããã®ã¿ã®ã¹ã¿ãã¯ãã¬ãŒã¹ãåé€ããããããããã¯æ£åžžã§ãã ãããŠã圌ã¯çµæãéåžžã«ã³ã³ãã¯ããªæ§é ã«è¿œå ããŸã-圌ã¯ã¡ãœãããã¯ã©ã¹ã®ããããã¹ãŠã®ååãçæããŸããã ããã¯ãã¹ãŠãå°å·æã«ã®ã¿èšç®ãããŸãã ãããŠããããã¡ã€ãªã³ã°äžã«ãjmethodIDïŒå®éã«ã¯ãã¡ãœãããžã®ãã€ã³ã¿ãŒïŒã®ã¿ãè¿œå ãããŸãã
ã¹ããªãŒã ãã³ã
ã¹ã¬ããããã³ãããæ¹æ³ã¯å€æ°ãããŸããJavaã³ãŒãããããã€ãã£ããããããã»ã¹èªäœã®äžããããŸãã¯å€éšããã
å
éšããããã»ã¹ãã€ãŸãJava API getAllStackTracesãåæããããšã«ã€ããŠè©±ãå ŽåãStackTraceElementã®é
åãšãããæå³ãããã¹ãŠãæäŸããŸãã

æ¬çªç°å¢ã§äœ¿çšããããšãããšãããããã50ã60ãã¬ãŒã ã®ã¹ã¿ãã¯æ·±åºŠãæã€2000ã¹ããªãŒã ã®å Žåããã®ã¢ã¬ã€ã ãã§çŽ50 Mbãå æããŸããã
JMXã«ã¯åæ§ã®æ¹æ³ããããŸãïŒãªã¢ãŒãã§ãã«ã§ãããšããç¹ã§äŸ¿å©ã§ãïŒã åãStackTraceElementé
åãšããã£ããã£ãããã¢ãã¿ãŒã«é¢ããæ
å ±ãè¿ããŸãã
ã¢ããªã±ãŒã·ã§ã³èªäœããã¹ã¿ãã¯ãã¬ãŒã¹ãçæããå Žåãã¯ããã«åªããæ¹æ³ã¯JVMTIïŒTool InterfaceïŒã§ããããã¯ãããŒã«ããããã¡ã€ã©ãŒãã¢ãã©ã€ã¶ãŒãªã©ãéçºããããã®ãã€ãã£ãã€ã³ã¿ãŒãã§ã€ã¹ã§ãã

éåžžããããã¡ã€ã©ãŒã®ã¿ã䜿çšããGetAllStackTracesã¡ãœããããããŸãã Java APIãšæ¯èŒãããšãéåžžã«ã³ã³ãã¯ããªè¡šçŸã§ãã
ãã³ããå€éšããåé€ããå Žåãæãç°¡åãªæ¹æ³ã¯SIGQUITããã»ã¹ãéä¿¡ããããšã§ãïŒkill -3ãŸãã¯ã³ã³ãœãŒã«ã§é©åãªçµã¿åããã®ããããïŒã

ãã®æ¹æ³ã®å©ç¹ã¯ãJavaãã·ã³èªäœãã¹ã¿ãã¯ãã¬ãŒã¹ãåºåããããšã§ãã ããã¯æ倧é床ã§è¡ãããŸãã ãšã«ããããã¯ã»ãŒããã€ã³ãäžã«èµ·ãããŸãããäžéæ§é ãäœæããå¿
èŠã¯ãããŸããã
å¥ã®æ¹æ³ã¯jstackãŠãŒãã£ãªãã£ã§ãã ããã¯ãåçãªã¢ã¿ããã¡ã«ããºã ãä»ããŠæ©èœããŸãïŒè©³çŽ°ã«ã€ããŠã¯åŸè¿°ããŸãïŒã
jstackããã³jmapãŠãŒãã£ãªãã£ã«ã¯2ã€ã®åäœã¢ãŒããããããšãç解ããããšãéèŠã§ãã 1ã€ã®-Fã¹ã€ããã ããç°ãªããŸãããæ¬è³ªçã«ã¯åãæ©èœãæäŸãã2ã€ã®ç°ãªããŠãŒãã£ãªãã£ã§ããã2ã€ã®ãŸã£ããç°ãªãæ¹æ³ã§åäœããŸãã
ãããã®éãã¯äœã§ããã
ãã€ãããã¯ã¢ã¿ããã¯ãç¹å¥ãªã€ã³ã¿ãŒãã§ã€ã¹ãä»ããŠãŠãŒãã£ãªãã£ãJVMãšéä¿¡ããããã®ã¡ã«ããºã ã§ãã ããã¯ã©ã®ããã«èµ·ãããŸããïŒäŸãšããŠLinuxã䜿çšïŒïŒ

jstackãŠãŒãã£ãªãã£ã¯ãçŸåšã®ãã£ã¬ã¯ããªã«ç¹å®ã®ãã¡ã€ã«ãäœæããŸããããã¯ããŠãŒãã£ãªãã£ãJVMã«æ¥ç¶ããããšããã·ã°ãã«ã§ãããSIGQUITã·ã°ãã«ãä»®æ³ãã·ã³ã«éä¿¡ããŸãã ä»®æ³ãã·ã³ã¯ãã®ã·ã°ãã«ãåŠçããçŸåšã®ãã£ã¬ã¯ããªã«ãã.attach_pidã·ã°ãã«ãã¡ã€ã«ã確èªããããã«å¿çããŠãç¹å¥ãªã¹ã¬ããAttachListenerãèµ·åããŸãïŒæ¢ã«å®è¡ãããŠããå Žåã¯äœãããŸããïŒã ãŸãããã®ã¹ã¬ããã§ã¯ãjstackãŠãŒãã£ãªãã£ãšJVMéã®éä¿¡çšã«UNIXãã¡ã€ã³ãœã±ãããéããŸãã ãŠãŒãã£ãªãã£ããã®ãœã±ããã«æ¥ç¶ãããšãJVMã¯çžæåŽã®ãŠãŒã¶ãŒæš©éããã§ãã¯ããä»ã®ãŠãŒã¶ãŒãä»®æ³ãã·ã³ã«æ¥ç¶ããŠäœããã®å人æ
å ±ãååŸã§ããªãããã«ããŸãã ããããããã®ãã§ãã¯ã¯éåžžã«ç°¡åã§ã-æå¹ãªUIDãšGIDã®æ£ç¢ºãªå¯Ÿå¿ã®ã¿ããã§ãã¯ãããŸãïŒæçµçã«ã¯ãä»ã®ãŠãŒã¶ãŒïŒrootã§ããïŒããjstackãèµ·åãããšããã®ãã§ãã¯ã®ããã«æ£ç¢ºã«ãã³ããååŸã§ããªããšããäžè¬çãªåé¡ããããŸãïŒ
UNIXãœã±ããäžã®æ¥ç¶ã確ç«ãããåŸããŠãŒãã£ãªãã£ã¯ã³ãã³ããéä¿¡ããä»®æ³ãã·ã³ã¯ãã®ã³ãã³ããå®è¡ããå¿çã¯åããœã±ããäžã®ãŠãŒãã£ãªãã£ã«éãè¿ãããŸãã
Windowã§ã¯ãã¹ãŠãå°ãç°ãªãæ¹æ³ã§åäœããŸãïŒãªãåãããã«ã§ããªãã®ãããããŸãããWindowsã«ã¯UNIXãœã±ããã¯ãããŸããããååä»ããã€ãããããŸãïŒ-ç§ã奜ããªå¥ã®çŸããAPIããããŸãããã¡ãã
å§ãŸãã¯ã»ãŒåãã§ã-ååä»ããã€ããäœæãããŸãã ããã«ãWindows APIã«ã¯ãä»ã®ããã»ã¹ã«æš©éãããå Žåãå¥ã®ããã»ã¹ã®ã¡ã¢ãªã«ããŒã¿ãçŽæ¥æžã蟌ãããšãã§ããWriteProcessMemoryé¢æ°ããããŸãã ãã®é¢æ°ãä»ããŠãJavaããã»ã¹ã®ã¢ãã¬ã¹ç©ºéã«äžæçãªè£å©ã¡ã¢ãªããŒãžãäœæãããããã«å®è¡ãããã³ãã³ããåŒæ°ãããã³ãã€ãåãæžã蟌ãŸããŸãã ã¹ã¬ãããä»ã®èª°ãã®ããã»ã¹ã«å®è£
ã§ããããã«ãããã1ã€ã®åªããæ©èœã¯ãCreateRemoteThreadã§ãã jstackãŠãŒãã£ãªãã£ã¯ããªã¢ãŒãã¹ã¬ãããéå§ããŸããããã¯ãä»®æ³ãã·ã³ããã»ã¹ã®ã³ã³ããã¹ãã§æ¢ã«å®è¡ãããŠããŸãã ãããŠããã®ã¹ã¬ãããžã®åŒæ°ãšããŠã以åã«äœæãããã¡ã¢ãªé åã«ãã€ã³ã¿ãæž¡ãããããã«ã¯ã³ãã³ãã«é¢ãããã¹ãŠã®æ
å ±ããããŸãã
ãã®åŸããã¹ãŠãåãã«ãªããŸããJVMèªäœãã³ãã³ããå®è¡ããçµæãéãè¿ããŸãã

ãã®ã¢ãããŒãã®å©ç¹ïŒ
- ãã¹ãŠã®æäœã¯ãæãå¹ççãªæ¹æ³ã§ä»®æ³ãã·ã³ã«ãã£ãŠçŽæ¥å®è¡ãããŸãã
- ã€ã³ã¿ãŒãã§ã€ã¹ã¯VMã®ããŒãžã§ã³ã«äŸåããªãããã1ã€ã®jstackãŠãŒãã£ãªãã£ã¯ããããã®VMãå®è¡ãããŠããJavaã®ããŒãžã§ã³ã«é¢ä¿ãªããç°ãªãããã»ã¹ãããã³ããåé€ã§ããŸãã
æ¬ ç¹ã¯æ¬¡ã®ãšããã§ãã
- æ¢ã«è¿°ã¹ããŠãŒã¶ãŒã®ã³ã³ãã©ã€ã¢ã³ã¹éåã«é¢ããå¶éã
- ã³ãã³ãã¯ä»®æ³ãã·ã³èªäœã«ãã£ãŠå®è¡ãããããããã©ã€ããä»®æ³ãã·ã³äžã§ã®ã¿å®è¡ã§ããŸãã
- ãã®ã¡ã«ããºã ã¯ãç¹å¥ãªJVMãªãã·ã§ã³ã§ç¡å¹ã«ããããšãã§ããŸãïŒã»ãã¥ãªãã£äžã®çç±ãªã©ã«ããïŒã
-XX:+DisableAttachMechanism
ã
ãæŠå¿µå®èšŒããšããŠãç§ã¯Cã§ç°¡åãªãŠãŒãã£ãªãã£ãäœæããããšã«ããŸããããã®æ¹æ³ã§ãªã¢ãŒãJavaããã»ã¹ã«æ¥ç¶ããã³ãã³ãã©ã€ã³ïŒ
https://github.com/apangin/jattach ïŒã§æž¡ãããã³ãã³ããå®è¡ã
ãŸã ã
ä»®æ³ãã·ã³ã¯æ¬¡ã®ã³ãã³ãããµããŒãããŠããŸãã

ããã¯ãã¹ã¬ãããã³ããããããã³ããããããã¹ãã°ã©ã ã®ååŸãä»®æ³ãã·ã³ã®ãã©ã°ã®å°å·ãšèšå®ãjcmdãŠãŒãã£ãªãã£ãå®è¡ã§ããã³ãã³ãã®å®è¡ã§ããããŒãã¯ãããããJVMTIãšãŒãžã§ã³ãã©ã€ãã©ãªããªã¢ãŒãä»®æ³ãã·ã³ã«ããŒãã§ããæãèå³æ·±ãã³ãã³ãã§ãã
loadã³ãã³ãã䜿çšãããšãéåæãããã¡ã€ã©ãŒãæ©èœããŸãïŒã©ã€ãã©ãªããªã¢ãŒãJVMã«ã¢ããããŒãããŸãïŒããããã©ã®ããã«æ©èœããããç°¡åã«ç€ºããŸããtomcatãªã©ã®ããã»ã¹ãéå§ããŸããããã»ã¹pidã¯8856
ã§ããã³ãã³ãã§ã¹ããªãŒã ã®åããã³ããçºè¡ãããŸããããã¯JavaãŠãŒãã£ãªãã£ã§ã¯ãªãCãªã®ã§ãJavaã®èµ·åã«æéã浪費ããå¿
èŠã¯ãããŸããããã®ãŠãŒãã£ãªãã£ã¯éåžžã«çããWindowsããã³Linuxã§ã¯æåéã100è¡ã§ããGitHubã§å©çšã§ããŸãããã®ã¡ã«ããºã ã«ãããjstackãŠãŒãã£ãªãã£ã ãã§ãªããjmapãjinfoãjcmdãŠãŒãã£ãªãã£ãåäœããŸãïŒå®éãjattachã®1ã€ãããããã¹ãŠã®ãŠãŒãã£ãªãã£ã®åœ¹å²ãæãããŸãïŒã2çªç®ã®æ¹æ³ã¯jstack -Fã¢ãŒãã§ããJVMããã®ååããã¯ããªããšããç¹ã§ç°ãªããŸã-ãŠãŒãã£ãªãã£ã¯ãã¹ãŠãè¡ããŸããLinux PTRACE_ATTACH ( Windows ) , , . API, , jstack , , JVM . JVM , .
PTRACE_PEEKDATA 1 1 , , (, , ).

, :
- â jstack -F VM;
- root , .
:
- , ;
- jstack , , , jstack JVM, .

ããã¯äœã®ããã§ããïŒ , , - . (, thread pool), , , , .
Java API , . Dynamic Attach â Java API, jstack. pid , Dynamic Attach .
public static void dump() throws AttachNonSupportedException, IOException { String vmName = ManagementFactory.getRuntimeMXBean().getName(); String pid = vmName.substring(0, vmName.indexOf('@')); HotSpotVirtualMachine vm = (HotSpotvirtualMachine) VirtualMachine.attach(pid); try { vm.localDataDump(); } finally { vm.detach(); } }
GitHub :
https://github.com/odnoklassniki/one-nio/blob/master/src/one/nio/mgt/-
jmap .
jmap -dump:live,format=b,file=heap.bin PID
, , :

, . , . , .
jmap 2 : Dynamic Attach Serviceability Agent ( ).

jmap -F , , JVM. jmap -F , .
jmap? , - . , - , VM â , , . , Dynamic Attach . , , - , -F. . , . jmap , - .
, , forced-.
$ sudo gcore 1234
$ jmap -dump:format=b,file=heap.bin /path/to/java core.1234
, â , â core dump. . , . .
jmap «» core dump.
.
tomcat pid 2362. jmap forced-:

. . , gcore, core dump . 227 .
: , tomcat .
jmap core-.

, .. , , , ( , jmap -F, , 1 ). , , jmap -F .
, - , - . :
-XX:+HeapDumpOnOutOfMemoryError
â out of memory. GC , .
:

, .

, manageable, .. , jinfo, JMX-.

Java 8 update 92 2 - ( downtime ):

, , , , . 2 ( out of memory ):

?
java, native, , .
MXBean:
HotSpotDiagnosticMXBean bean = ManagementFactory.newPlatformMXBeanProxy( ManagementFactory.getPlatformMBeanServer(), "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class); bean.dumpHeap("/tmp/heap.bin", true);
JMX remote interface, .
: jmap , ssh - , , â JMX remote interface.
JVMTI.
IterateOverInstancesOfClass .

, - . , , 16 .
, . , , .
GetObjectsWithTags jobject.
â serviceability agent â API, HotSpot. JDK JVM, Java-.

Java sa-jdi.jar â API serviceability agent. : JVM, , Java API, . , VM .
äŸãèŠãŠã¿ãŸãããã
, â , . - , , . , , .. . serviceability agent .
API .
package demo6; import sun.jvm.hotspot.oops.DefaultHeapVisitor; import sun.jvm.hotspot.oops.Klass; import sun.jvm.hotspot.oops.Oop; import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.tools.Tool; public class KeyScanner extends Tool { @Override public void run() { Klass klass = VM.getVM().getSystemDictionary().find("java/security/PrivateKey", null, null); VM.getVM().getObjectHeap().iterateObjectsOfKlass(new DefaultHeapVisitor() { @Override public boolean doObj(Oop oop) { oop.iterate(new FieldPrinter("key"), false); return false; } }, klass); } public static void main(String[] args) { new KeyScanner().execute(args); } }
( Tool), execute ( ). run .
serviceability agent, Java-. .
tomcat .
â , .

, , . Print , .

. FieldPrinter, , fieldName, .
package demo6; import sun.jvm.hotspot.oops.DefaultOopVisitor; import sun.jvm.hotspot.oops.OopField; import sun.jvm.hotspot.oops.TypeArray; public class FieldPrinter extends DefaultOopVisitor { private String fieldName; FieldPrinter(String fieldName) { this.fieldName = fieldName; } @Override public void doOop(OopField field, boolean isVMField) { if (field.getID().getName().equals(fieldName)) { TypeArray array = (TypeArray) field.getValue(getObj()); long length = array.getLength(); System.out.print(fieldName + ": "); for (long i = 0; i < length; i++) { System.out.printf("%02x", array.getByteAt(i)); } System.out.println(); } } }
private key .
serviceability agent , API . , : , , oldGen. serviceability agent , API. Java- oldGen, , oldGen, .
tomcat, oldGen:
package demo6; import sun.jvm.hotspot.gc_implementation.parallelScavenge.PSOldGen; import sun.jvm.hotspot.gc_implementation.parallelScavenge.ParallelScavengeHeap; import sun.jvm.hotspot.gc_interface.CollectedHeap; import sun.jvm.hotspot.oops.DefaultHeapVisitor; import sun.jvm.hotspot.oops.Klass; import sun.jvm.hotspot.oops.Oop; import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.tools.Tool; public class OldGen extends Tool { @Override public void run() { CollectedHeap heap = VM.getVM().getUniverse().heap(); PSOldGen oldGen = ((ParallelScavengeHeap) heap).oldGen(); Klass klass = VM.getVM().getSystemDictionary().find("java/lang/String", null, null); VM.getVM().getObjectHeap().iterateObjectsOfKlass(new DefaultHeapVisitor() { @Override public boolean doObj(Oop oop) { if (oldGen.isIn(oop.getHandle())) { oop.printValue(); System.out.println(); } return false; } }, klass); } public static void main(String[] args) { new OldGen().execute(args); } }
:
.
â 7-8 JPoint 2017 . « JVM- », , , . «» , !
, JPoint Java â , .