# openjdk **Repository Path**: wang-yi-656/openjdk ## Basic Information - **Project Name**: openjdk - **Description**: OpenJDK做为GPL许可(GPL-licensed)的Java平台的实现,Sun正式发布它已经一年有余 - **Primary Language**: Java - **License**: GPL-2.0 - **Default Branch**: recorder - **Homepage**: https://www.oschina.net/p/openjdk - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 203 - **Created**: 2023-09-06 - **Last Updated**: 2025-04-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 这个分支源码编译出来的jdk既可以记录内存操作,又可以记录运行时的Java类结构信息 # 一 如何编译jdk源码 #### 工具版本参考 * Boot JDK: openjdk version "17.0.2" 2022-01-18 OpenJDK Runtime Environment (build 17.0.2+8-86) OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing) * Toolchain: gcc (GNU Compiler Collection) * C Compiler: Version 8.5.0 (at /bin/gcc) * C++ Compiler: Version 8.2.1 (at /bin/g++) #### 编译参数: >bash configure --enable-option-checking=fatal --with-extra-cxxflags=-Wno-error --with-extra-cflags=-Wno-error --disable-warnings-as-errors --with-debug-level=release >make 编译jdk过程可能会出现 "Failed to open the file. Please check CLASS_PATH environment." 属于正常现象,不影响正常编译,如果想要让这个信息不出现,则增加export CLASS_PATH="./class.txt" # 二 如何在插桩的JVM上运行Java程序 使用未插桩的java编译运行程序。 ```shell # 这里举一个模拟Web场景程序的例子(源程序为example目录下的Test.java程序) cd example javac Test.java ``` 使用插桩后的java运行javac编译后的程序。 当前的pwd目录还是在example目录下 ```shell # CLASS_PATH为想要输出类结构信息到哪个文件,例子是输出类结构信息到./class.txt文件 > export CLASS_PATH="./class.txt" > ../build/linux-x86_64-server-release/jdk/bin/java -Xint -XX:+UseParallelGC -Xms32G -Xmx32G -Xlog:gc*:file=trace.txt::filesize=200000g,filecount=500 Test ``` 内存操作记录见trace.txt(如果记录文件被分为多个文件, 如result.txt.00, result.txt.01,则增加参数filesize的大小,使得trace.txt始终是一个文件), class信息见class.txt 由此我们可以在example目录下获得两个输出文件 * **trace.txt**:内存操作记录信息 * **class.txt**:类结构信息 # 参考信息 ### Trace语句含义及示例(2023.10.18版): #### 1、新建对象 ##### 1.1 new普通对象 New H:Hashcode, S:Size, C:Class, T:Thread, M:方法所属类.方法名 (参数1类名;参数2类名;···参数n类名;)返回值类名;(注:返回值为基础类型时,无结尾分号,后面的处理相同不再赘述) 示例: New H:0x000000006be78a46, S:4, C:java/util/HashMap$Node, T:main, M:java/util/HashMap.newNode (ILjava/lang/Object;Ljava/lang/Object;Ljava/util/HashMap$Node;)Ljava/util/HashMap$Node; ##### 1.2 new一维数组 New H:Hashcode, S:Size, C:Class, D:数组元素个数, T:Thread, M:方法所属类.方法名 (参数1类名;参数2类名;···参数n类名;)返回值类名;(注:返回值为基础类型时,无结尾分号,后面的处理相同不再赘述) ``` 示例: New H:0x000000000ea1a8d5, S:4, C:[Ljava/lang/Stri, D:3, T:main, M:sun/nio/cs/StandardCharsets.aliases_UTF_16LE ()[Ljava/lang/String; ``` ##### 1.3 new多维数组 由NewM与NewL共同表示,第一个NewM提醒有一个多维数据创建,接着的NewL创建这个多维数组,后续的NewL创建低维度的数组 * NewM NewM C:Class, D:每个维度的元素个数 , T:Thread, M:方法所属类.方法名 (参数1类名;参数2类名;···参数n类名;)返回值类名;(注:返回值为基础类型时,无结尾分号,后面的处理相同不再赘述) * NewL NewL H:Hashcode, C:Class, R:几维数组, S:元素个数, T:Thread ``` [2023-10-18T16:24:17.671+0800][2.950s][info][gc,heap ] NewM C:[[Ljava/lang/invoke/LambdaForm$Name;, D:5 10 , T:main, M:java/lang/invoke/LambdaForm. ()V [2023-10-18T16:24:17.671+0800][2.950s][info][gc,heap ] NewL H:0x0000000046cdf8bd, C:[[Ljava/lang/invoke/LambdaForm$Name;, R:2, S:5, T:main [2023-10-18T16:24:17.671+0800][2.950s][info][gc,heap ] NewL H:0x000000000f0c8a99, C:[Ljava/lang/invoke/LambdaForm$Name;, R:1, S:10, T:main [2023-10-18T16:24:17.671+0800][2.950s][info][gc,heap ] PutA H1:0x0000000046cdf8bd, C1:[[Ljava/lang/invoke/LambdaForm$Name;, H2:0x000000000f0c8a99, C2:[Ljava/lang/invoke/LambdaForm$Name;, O:0, T:main, M:java/lang/invoke/LambdaForm. ()V ``` #### 2、写对象引用 A.o = B Put H1:A的Hashcode, C1:A类, IS:是否为static字段(true表示为static字段、false表示为实例字段), H2:B的Hashcode, C2:B类, F:field名称, T:Thread, M:方法所属类.方法名 (参数1类名;参数2类名;···参数n类名;)返回值类名; 示例: Put H1:0x000000003de64145, C1:java/lang/module/Configuration, IS:false, H2:0x000000001ecd979e, C2:java/util/ImmutableCollections$List12, F:conf, T:main, M:java/lang/module/Configuration. (Ljava/util/List;Ljava/lang/module/Resolver;)V #### 3、写数组引用 A[o] = B PutA H1:A的Hashcode, C1:A类(注:数组类名自带后缀";"), H2:B的Hashcode, C2:B类, O:偏移, T:Thread, M:方法所属类.方法名 (参数1类名;参数2类名;···参数n类名;)返回值类名; 示例: PutA H1:0x00000000468f8309, C1:[Ljava/util/Map$Entry;, H2:0x000000004d425872, C2:java/util/KeyValueHolder, O:63, T:main, M:java/lang/module/Configuration. (Ljava/util/List;Ljava/lang/module/Resolver;)V #### 4、classloader根对象 ##### 4.1 classloader根对象增加 Add Class root H:Hashcode, D:classloaderdata名称, S:size, C:class; 示例: Add Class root H:0x0000000007e7c780, D:unknown, S:3, C:[Ljava/lang/Object; ##### 4.2 classloader根对象删除 Del Class root H:Hashcode, D:classloaderdata名称; #### 5、oopstorage根对象 ##### 5.1 oopstorage根对象增加 Add Set root H:Hashcode Set:Oopstorageset名称(可能含有空格) Size:size C:class, A:address 示例: Add Set root H:0x00000000251a69d7 Set:VM Global Size:14 C:java/lang/Class, A:0x00007f3b4c09d040 ##### 5.2 oopstorage根对象删除 Del Set root H:Hashcode Set:Oopstorageset名称 A:address ##### 5.3 oopstorage根对象替换 Rep Set root H:Hashcode A:addressto H:Hashcode #### 6、栈帧对象 ##### 6.1 local root对象增加或替换 Add LR H:Hashcode, C:Class, T:Thread, R:原local位置对象hashcode(注:若为NULL代表为新增), M:方法所属类.方法名 (参数1类名;参数2类名;···参数n类名;)返回值类名; 示例: Add LR H:0x000000004edde6e5, C:java/lang/ThreadGroup, T:main, R: NULL, M:java/lang/ThreadGroup.addUnstarted ()V ##### 6.2 parameter root对象新增 Add PR H:Hashcode, C:Class, T:Thread, M:方法所属类.方法名 (参数1类名;参数2类名;···参数n类名;)返回值类名; 示例: Add PR H:0x000000004be490da, C:java/lang/module/ModuleDescriptor, T:main, M:java/util/HashMap.put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; ##### 6.3 方法返回值记录 Return H:hashcode, C:class, T:thread 示例: Return H:0x000000001e80bfe8, C:java/lang/ThreadGroup, T:main ##### 6.4 local root对象删除 Del LR H:hashcode, C:class, T:thread, M:方法所属类.方法名 (参数1类名;参数2类名;···参数n类名;)返回值类名; 示例: Del LR H:0x000000001e80bfe8, C:java/lang/ThreadGroup, T:main, M:java/lang/ThreadGroup.addUnstarted ()V ### 类型说明 class信息结果中, 记录的是java类型签名, 其对应的java类型如下: | Type Signature | Java Type | | ------------------------- | --------------------- | | Z | boolean | | B | byte | | C | char | | S | short | | I | int | | J | long | | F | float | | D | double | | L fully-qualified-class ; | fully-qualified-class | | fully-qualified-class [] | type[] | | ( arg-types ) ret-type | method type |