├── .gitignore
├── LICENSE
├── README.md
├── core
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── org
│ │ └── adoptopenjdk
│ │ └── jheappo
│ │ ├── io
│ │ ├── AllocSites.java
│ │ ├── CPUSamples.java
│ │ ├── ControlSettings.java
│ │ ├── EncodedChunk.java
│ │ ├── EndThread.java
│ │ ├── HeapDumpEnd.java
│ │ ├── HeapDumpSegment.java
│ │ ├── HeapProfile.java
│ │ ├── HeapProfileHeader.java
│ │ ├── HeapProfileRecord.java
│ │ ├── HeapSummary.java
│ │ ├── LoadClass.java
│ │ ├── StackFrame.java
│ │ ├── StackTrace.java
│ │ ├── StartThread.java
│ │ ├── UTF8StringSegment.java
│ │ └── UnloadClass.java
│ │ ├── model
│ │ ├── ArrayValue.java
│ │ ├── BasicDataTypeValue.java
│ │ ├── BooleanValue.java
│ │ ├── ByteValue.java
│ │ ├── CharValue.java
│ │ ├── DoubleValue.java
│ │ ├── FloatValue.java
│ │ ├── IntValue.java
│ │ ├── LongValue.java
│ │ ├── ObjectValue.java
│ │ ├── PrimitiveValue.java
│ │ ├── ShortValue.java
│ │ └── UnknownValue.java
│ │ └── objects
│ │ ├── BasicDataTypes.java
│ │ ├── ClassObject.java
│ │ ├── HeapObject.java
│ │ ├── InstanceObject.java
│ │ ├── ObjectArray.java
│ │ ├── PrimitiveArray.java
│ │ ├── RootJNIGlobal.java
│ │ ├── RootJNILocal.java
│ │ ├── RootJavaFrame.java
│ │ ├── RootMonitorUsed.java
│ │ ├── RootNativeStack.java
│ │ ├── RootStickyClass.java
│ │ ├── RootThreadBlock.java
│ │ ├── RootThreadObject.java
│ │ ├── RootUnknown.java
│ │ └── UTF8String.java
│ └── test
│ └── java
│ └── org
│ └── adoptopenjdk
│ └── jheappo
│ └── io
│ └── HeapDumpSectionTest.kt
├── data
├── HeapDumpSegment.hprof
└── mastermind.hprof
├── pom.xml
└── tools
├── pom.xml
└── src
├── main
└── java
│ └── org
│ └── adoptopenjdk
│ └── jheappo
│ ├── Heappo.java
│ └── model
│ ├── HeapGraph.java
│ ├── HeapGraphExtras.java
│ └── JavaHeap.java
└── test
├── java
└── org
│ └── adoptopenjdk
│ └── jheappo
│ └── heaptextoutput
│ └── HeapDumpTextTest.kt
└── resources
└── org
└── adoptopenjdk
└── jheappo
└── heaptextoutput
├── class.table
├── heap.dump
├── instance.table
├── loadClass.table
└── string.table
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX files
2 | *DS_Store
3 |
4 | #IDE
5 | .idea/*
6 | *.iml
7 |
8 | # Compiled class file
9 | *.class
10 |
11 | # Log file
12 | *.log
13 |
14 | # BlueJ files
15 | *.ctxt
16 |
17 | # Mobile Tools for Java (J2ME)
18 | .mtj.tmp/
19 |
20 | # Package Files #
21 | *.jar
22 | *.war
23 | *.ear
24 | *.zip
25 | *.tar.gz
26 | *.rar
27 |
28 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
29 | hs_err_pid*
30 |
31 | /target
32 | */target
33 | dependency-reduced-pom.xml
34 |
35 | /tmp
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # jheappo
2 | A Heap Dump Parser
3 |
4 |
5 | ## Neo4j Export
6 |
7 | run Heappo and add the "graph" parameter
8 |
9 | `java -jar path/to/jheappo.jar "/path/to/file.hprof" graph`
10 |
11 | It will create a `graph.db` directory.
12 |
13 | The graph model is:
14 |
15 | ```
16 | (:Class {id, name, _fields})-[:SUPERCLASS]->(:Class)
17 | (:Instance {id, _fields})-[:IS_CLASS]->(:Class)
18 | (:Instance)-[:CONTAINS]->(:Instance)
19 | ```
20 |
21 |
22 | ### Query Graph Console
23 |
24 | You can open it directly with neo4j-shell:
25 |
26 | `$NEO4J_HOME/bin/neo4j-shell -path graph.db`
27 |
28 | and then run queries like:
29 |
30 | ```
31 | ~/v/neo4j-enterprise-3.3.3/bin/neo4j-shell -path graph.db
32 | NOTE: Local Neo4j graph database service at 'graph.db'
33 |
34 | match (c:Class) return c limit 5;
35 | +---------------------------------------------------------------------------------------------------------------------------------------------------+
36 | | c |
37 | +---------------------------------------------------------------------------------------------------------------------------------------------------+
38 | | Node[0]{id:28991131920,name:"sun/lwawt/macosx/CPlatformWindow$$Lambda$33",size:8,_arg$1:2} |
39 | | Node[1]{size:0,id:28991103008,name:"java/lang/Object"} |
40 | | Node[2]{id:28991132048,name:"sun/java2d/opengl/CGLLayer$$Lambda$32",size:0} |
41 | | Node[3]{id:28991132200,name:"java/lang/invoke/LambdaForm$MH",size:0} |
42 | | Node[4]{id:28991132328,name:"java/lang/invoke/LambdaForm$DMH",size:0} |
43 | | Node[5]{id:28991132456,name:"java/lang/invoke/LambdaForm$DMH",size:0} |
44 | | Node[6]{_arg$5:2,_arg$4:2,_arg$3:2,_arg$2:10,id:28991132584,name:"com/apple/laf/AquaPainter$AquaSingleImagePainter$$Lambda$31",size:32,_arg$1:10} |
45 | +---------------------------------------------------------------------------------------------------------------------------------------------------+
46 |
47 | match (c:Class) where not c.name starts with "java/lang/invoke/LambdaForm" return c limit 100;
48 |
49 | match (c:Class) where c.name = "java/lang/Object" return c;
50 |
51 | match (c:Class) where c.name = "java/lang/Object" return c, size( (c)<-[:IS_CLASS]-() );
52 |
53 | match (c:Instance) return count(*);
54 | +----------+
55 | | count(*) |
56 | +----------+
57 | | 38359 |
58 | +----------+
59 | 1 row
60 | 70 ms
61 | match (c:Instance) where not (c)<-[:CONTAINS]-() return count(*);
62 | +----------+
63 | | count(*) |
64 | +----------+
65 | | 14611 |
66 | +----------+
67 | 1 row
68 | 213 ms
69 |
70 | match (i:Instance)-[:IS_CLASS]->(c) where not (i)<-[:CONTAINS]-() return c.name, i limit 10;;
71 | +------------------------------------------------------------------------------------------------+
72 | | c.name | i |
73 | +------------------------------------------------------------------------------------------------+
74 | | "java/util/concurrent/locks/ReentrantLock" | Node[2188]{stackSerial:1,id:28991029248} |
75 | | "java/lang/String" | Node[2190]{stackSerial:1,id:28991029264,_hash:0} |
76 | | "java/lang/String" | Node[2195]{stackSerial:1,id:28991030104,_hash:0} |
77 | | "java/lang/String" | Node[2197]{stackSerial:1,id:28991030672,_hash:0} |
78 | | "java/lang/String" | Node[2199]{stackSerial:1,id:28991030696,_hash:0} |
79 | | "java/lang/String" | Node[2201]{stackSerial:1,id:28991030720,_hash:0} |
80 | | "java/lang/StringBuilder" | Node[2203]{stackSerial:1,id:28991031944} |
81 | | "java/lang/String" | Node[2204]{stackSerial:1,id:28991031968,_hash:0} |
82 | | "java/lang/String" | Node[2206]{stackSerial:1,id:28991031992,_hash:0} |
83 | | "sun/awt/SunHints$Value" | Node[2213]{stackSerial:1,id:28991032064,_index:2} |
84 | +------------------------------------------------------------------------------------------------+
85 | 10 rows
86 | 52 ms
87 |
88 |
89 | match (c:Class) return c.name, size( (c)<-[:IS_CLASS]-() ) as instances order by instances desc limit 10;
90 | +-----------------------------------------------------------+
91 | | c.name | instances |
92 | +-----------------------------------------------------------+
93 | | "java/lang/String" | 7968 |
94 | | "java/util/Hashtable$Entry" | 1805 |
95 | | "java/util/concurrent/ConcurrentHashMap$Node" | 1348 |
96 | | "java/util/HashMap$Node" | 1323 |
97 | | "java/lang/ref/SoftReference" | 1123 |
98 | | "java/util/concurrent/ConcurrentHashMap" | 838 |
99 | | "java/lang/ref/Finalizer" | 815 |
100 | | "sun/font/Font2DHandle" | 793 |
101 | | "sun/font/CFont" | 785 |
102 | | "java/lang/reflect/Field" | 561 |
103 | +-----------------------------------------------------------+
104 | 10 rows
105 | 12 ms
106 | ```
107 |
108 | ### Graph Visualization
109 |
110 | Ìf you want to see the graph visually, download and install Neo4j(Desktop) and create an new "Graph" in your "Project"
111 |
112 | Then go to "Manager" -> "Open Folder" and copy the `graph.db` directory into `data/database/graph.db`
113 |
114 | Then you can start the server and "Open Neo4j Browser" to execute queries and interactively visualize the data.
115 |
116 | Note: As the Heap graph is very large and dense, Neo4j browser's default visualization will come to its limits quickly.
117 |
118 | Then you need to add LIMIT's or filter / group data.
119 |
120 |
--------------------------------------------------------------------------------
/core/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 | * This is used by various hprof record types representing stack frames, objects in the heap, etc to decode the 13 | * corresponding components (e.g. id numbers). Notably, most things are represented as unsigned ints, which we cannot 14 | * represent well (yet). 15 | *
16 | * See https://hg.openjdk.java.net/jdk/jdk/file/9a73a4e4011f/src/hotspot/share/services/heapDumper.cpp for details on
17 | * the format.
18 | */
19 | public class EncodedChunk {
20 | private final byte[] body;
21 | private int index;
22 |
23 | public EncodedChunk(byte[] body) {
24 | this(body, 0);
25 | }
26 |
27 | private EncodedChunk(byte[] body, int index) {
28 | this.body = body;
29 | this.index = index;
30 | }
31 |
32 | public byte[] read(int bufferLength) {
33 | byte[] buffer = new byte[bufferLength];
34 | for (int i = 0; i < bufferLength; i++) {
35 | buffer[i] = (byte) (body[index++] & 0xff);
36 | }
37 |
38 | return buffer;
39 | }
40 |
41 | protected byte[] getBody() {
42 |
43 | return body;
44 | }
45 |
46 | public void skip(int skipOver) {
47 |
48 | index += skipOver;
49 | }
50 |
51 | public byte[] readRemaining() {
52 |
53 | return read(body.length - index);
54 | }
55 |
56 | public int getIndex() {
57 | return index;
58 | }
59 |
60 | public boolean endOfBuffer() {
61 |
62 | return getBody().length <= index;
63 | }
64 |
65 | private int read() {
66 |
67 | return body[index++] & 0xff;
68 | }
69 |
70 | public byte extractU1() {
71 |
72 | return (byte) read();
73 | }
74 |
75 | public short extractU2() {
76 | int value = extractU1();
77 |
78 | for (int cursor = 1; cursor < 2; cursor++) {
79 | value = (value << 8) | (short) read();
80 | }
81 |
82 | return (short) value;
83 | }
84 |
85 | public int extractU4() {
86 | int value = extractU1();
87 | for (int cursor = 1; cursor < 4; cursor++) {
88 | value = (value << 8) | read();
89 | }
90 |
91 | return value;
92 | }
93 |
94 | public long extractU8() {
95 | long value = extractU1();
96 | for (int cursor = 1; cursor < 8; cursor++) {
97 | value = (value << 8) | (long) read();
98 | }
99 |
100 | return value;
101 | }
102 |
103 | public long extractID() {
104 |
105 | return extractU8();
106 | }
107 |
108 | public boolean extractBoolean() {
109 |
110 | return extractU1() != 0;
111 | }
112 |
113 | public char extractChar() {
114 |
115 | return (char) extractU2();
116 | }
117 |
118 | public byte extractByte() {
119 |
120 | return extractU1();
121 | }
122 |
123 | public short extractShort() {
124 |
125 | return extractU2();
126 | }
127 |
128 | public float extractFloat() {
129 |
130 | return Float.intBitsToFloat(extractInt());
131 | }
132 |
133 | public int extractInt() {
134 |
135 | return extractU4();
136 | }
137 |
138 | public double extractDouble() {
139 |
140 | return Double.longBitsToDouble(extractLong());
141 | }
142 |
143 | public long extractLong() {
144 | return extractU8();
145 | }
146 |
147 | public BasicDataTypeValue extractBasicType(BasicDataTypes basicType) {
148 |
149 | switch (basicType) {
150 | case BOOLEAN:
151 |
152 | return new BooleanValue(this.extractBoolean());
153 | case CHAR:
154 |
155 | return new CharValue(this.extractChar());
156 | case BYTE:
157 |
158 | return new ByteValue(this.extractByte());
159 | case SHORT:
160 |
161 | return new ShortValue(this.extractShort());
162 | case FLOAT:
163 |
164 | return new FloatValue(this.extractFloat());
165 | case INT:
166 |
167 | return new IntValue(this.extractInt());
168 | case OBJECT:
169 |
170 | return new ObjectValue(this.extractID());
171 | case DOUBLE:
172 |
173 | return new DoubleValue(this.extractDouble());
174 | case LONG:
175 |
176 | return new LongValue(this.extractLong());
177 | default:
178 |
179 | return new UnknownValue();
180 | }
181 | }
182 |
183 | public BasicDataTypeValue extractBasicType(int basicType) {
184 | return extractBasicType(BasicDataTypes.fromInt(basicType));
185 | }
186 |
187 | /**
188 | * Useful when you want to read some bytes without affecting the internal cursor position.
189 | *
190 | * @return A chunk with the same byte array and offset as this object.
191 | */
192 | public EncodedChunk copy() {
193 |
194 | return new EncodedChunk(body, index);
195 | }
196 |
197 | /*
198 | Debugging aid
199 | */
200 | public void dump(PrintStream out) {
201 | int max = (body.length > 1000) ? 1000 : body.length;
202 | IntStream.range(0, max)
203 | .forEach(cursor -> {
204 | System.out.print(Integer.toHexString(body[cursor] & 255));
205 | System.out.print(" ");
206 | });
207 | out.println();
208 | IntStream.range(0, max)
209 | .forEach(cursor -> {
210 | System.out.print((char) (body[cursor] & 255));
211 | System.out.print(" ");
212 | });
213 | out.println();
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/EndThread.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 |
4 | public class EndThread extends HeapProfileRecord {
5 | public static final int TAG = 0x0B;
6 |
7 | public EndThread(EncodedChunk body){}
8 | }
9 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/HeapDumpEnd.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 |
4 | public class HeapDumpEnd extends HeapProfileRecord {
5 | public static final int TAG = 0x2C;
6 |
7 | public HeapDumpEnd(EncodedChunk body) {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/HeapDumpSegment.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 |
4 | import org.adoptopenjdk.jheappo.objects.*;
5 |
6 | /*
7 | ROOT UNKNOWN | 0xFF | ID | object ID
8 |
9 | ROOT JNI GLOBAL | 0x01 | ID | object ID
10 | | ID | JNI global ref ID
11 |
12 | ROOT JNI LOCAL | 0x02 | ID | object ID
13 | | u4 | thread serial number
14 | | u4 | frame number in stack trace (-1 for empty)
15 |
16 | ROOT JAVA FRAME | 0x03 | ID | object ID
17 | | u4 | thread serial number
18 | | u4 | frame number in stack trace (-1 for empty)
19 |
20 | ROOT NATIVE STACK | 0x04 | ID | object ID
21 | | u4 | thread serial number
22 |
23 | ROOT STICKY CLASS | 0x05 | ID | object ID
24 |
25 | ROOT THREAD BLOCK | 0x06 | ID | object ID
26 | | u4 | thread serial number
27 |
28 | ROOT MONITOR USED | 0x07 | ID | object ID
29 |
30 | ROOT THREAD OBJECT | 0x08 | ID | thread object ID
31 | | u4 | thread serial number
32 | | u4 | stack trace serial number
33 |
34 | CLASS DUMP | 0x20 | ID | class object ID
35 | | u4 | stack trace serial number
36 | | ID | super class object ID
37 | | ID | class loader object ID
38 | | ID | signers object ID
39 | | ID | protection domain object ID
40 | | ID | reserved
41 | | ID | reserved
42 | | u4 | instance size (in bytes)
43 | | u2 | size of constant pool and number of records that follow:
44 | | u2 | constant pool index
45 | | u1 | type of entry: (See Basic Type)
46 | | value | value of entry (u1, u2, u4, or u8 based on type of entry)
47 | | u2 | Number of static fields:
48 | | ID | static field name string ID
49 | | u1 | type of field: (See Basic Type)
50 | | value | value of entry (u1, u2, u4, or u8 based on type of field)
51 | | u2 | Number of instance fields (not including super class's)
52 | | ID | field name string ID
53 | | u1 | type of field: (See Basic Type)
54 |
55 |
56 | INSTANCE DUMP | 0x21 | ID | object ID
57 | | u4 | stack trace serial number
58 | | ID | class object ID
59 | | u4 | number of bytes that follow
60 | |[value]* | instance field values (this class, followed by super class, etc)
61 |
62 | OBJECT ARRAY DUMP | 0x22 | ID | array object ID
63 | | u4 | stack trace serial number
64 | | u4 | number of elements
65 | | ID | array class object ID
66 | | [ID]* | elements
67 |
68 | PRIMITIVE ARRAY DUMP | 0x23 | ID | array object ID
69 | | u4 | stack trace serial number
70 | | u4 | number of elements
71 | | u1 | element type (See Basic Type)
72 | | [u1]* | elements (packed array)
73 |
74 |
75 |
76 | Basic Types
77 |
78 | 2 | object
79 | 4 | boolean
80 | 5 | char
81 | 6 | float
82 | 7 | double
83 | 8 | byte
84 | 9 | short
85 | 10 | int
86 | 11 | long
87 |
88 | */
89 | public class HeapDumpSegment extends HeapProfileRecord {
90 | public static final int TAG1 = 0x0C;
91 | public static final int TAG2 = 0x1C;
92 |
93 | private final EncodedChunk body;
94 |
95 | public HeapDumpSegment(EncodedChunk body) {
96 | this.body = body;
97 | }
98 |
99 | public boolean hasNext() {
100 | return body.endOfBuffer();
101 | }
102 |
103 | public HeapObject next() {
104 | int typeCode = body.extractU1();
105 | switch (typeCode) {
106 | case RootUnknown.TAG:
107 | return new RootUnknown(body);
108 | case RootJNIGlobal.TAG:
109 | return new RootJNIGlobal(body);
110 | case RootJNILocal.TAG:
111 | return new RootJNILocal(body);
112 | case RootJavaFrame.TAG:
113 | return new RootJavaFrame(body);
114 | case RootNativeStack.TAG:
115 | return new RootNativeStack(body);
116 | case RootStickyClass.TAG:
117 | return new RootStickyClass(body);
118 | case RootThreadBlock.TAG:
119 | return new RootThreadBlock(body);
120 | case RootMonitorUsed.TAG:
121 | return new RootMonitorUsed(body);
122 | case RootThreadObject.TAG:
123 | return new RootThreadObject(body);
124 | case ClassObject.TAG:
125 | return new ClassObject(body);
126 | case InstanceObject.TAG:
127 | return new InstanceObject(body);
128 | case ObjectArray.TAG:
129 | return new ObjectArray(body);
130 | case PrimitiveArray.TAG:
131 | return new PrimitiveArray(body);
132 | default:
133 | System.out.println(typeCode + " not recognized... @index=" + body.getIndex());
134 | return null;
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/HeapProfile.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.DataInputStream;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.nio.file.Path;
8 |
9 |
10 | public final class HeapProfile {
11 | private final Path path;
12 | private final DataInputStream input;
13 | private boolean heapDumpEnd = false;
14 |
15 | public HeapProfile(Path path, DataInputStream input) {
16 | this.path = path;
17 | this.input = input;
18 | }
19 |
20 | public boolean isAtHeapDumpEnd() throws IOException {
21 |
22 | return heapDumpEnd || input.available() == 0;
23 | }
24 |
25 | public HeapProfileHeader readHeader() throws IOException {
26 | var header = new HeapProfileHeader();
27 | header.extract(input);
28 |
29 | return header;
30 | }
31 |
32 | private EncodedChunk readBody(DataInputStream inputStream, int bufferLength) throws IOException {
33 | byte[] buffer = new byte[bufferLength];
34 | int bytesRead = inputStream.read(buffer);
35 |
36 | if (bytesRead < bufferLength) {
37 | this.heapDumpEnd = true;
38 |
39 | throw new IOException("bytes request exceeded bytes read");
40 | } else {
41 |
42 | return new EncodedChunk(buffer);
43 | }
44 | }
45 |
46 | public HeapProfileRecord extract() throws IOException {
47 | byte tag = (new EncodedChunk(new byte[]{this.input.readByte()})).extractU1();
48 | long timeStamp = (long) this.input.readInt();
49 | int bodySize = this.input.readInt();
50 |
51 | final var body = readBody(input, bodySize);
52 |
53 | switch (tag) {
54 | case UTF8StringSegment.TAG:
55 |
56 | return new UTF8StringSegment(body);
57 | case LoadClass.TAG:
58 |
59 | return new LoadClass(body);
60 | case UnloadClass.TAG: {
61 | System.out.println("UnloadClass");
62 |
63 | return new UnloadClass(body);
64 | }
65 | case StackFrame.TAG:
66 |
67 | return new StackFrame(body);
68 | case StackTrace.TAG:
69 |
70 | return new StackTrace(body);
71 | case AllocSites.TAG: {
72 | System.out.println("AllocSites");
73 |
74 | return new AllocSites(body);
75 | }
76 | case HeapSummary.TAG: {
77 | System.out.println("HeapSummary");
78 |
79 | return new HeapSummary(body);
80 | }
81 | case StartThread.TAG: {
82 | System.out.println("StartThread");
83 |
84 | return new StartThread(body);
85 | }
86 | case HeapDumpSegment.TAG1:
87 | case HeapDumpSegment.TAG2:
88 |
89 | return new HeapDumpSegment(body);
90 | case HeapDumpEnd.TAG: {
91 | System.out.println("HeapDumpEnd");
92 | heapDumpEnd = true;
93 |
94 | return new HeapDumpEnd(body);
95 | }
96 | case CPUSamples.TAG: {
97 | System.out.println("CPUSamples");
98 |
99 | return new CPUSamples(body);
100 | }
101 | case ControlSettings.TAG: {
102 | System.out.println("ControlSettings");
103 |
104 | return new ControlSettings(body);
105 | }
106 | default:
107 | throw new IOException("Unknown record type " + tag);
108 | }
109 |
110 | }
111 |
112 | @Override
113 | public String toString() {
114 |
115 | return path.toString();
116 | }
117 |
118 | public static HeapProfile open(Path path, InputStream inputStream) {
119 | var input = new DataInputStream(new BufferedInputStream(inputStream));
120 |
121 | return new HeapProfile(path, input);
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/HeapProfileHeader.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 | /*
4 | * Copyright (c) 2018 Kirk Pepperdine.
5 | * Licensed under https://github.com/AdoptOpenJDK/jheappo/blob/master/LICENSE
6 | * Instructions: https://github.com/AdoptOpenJDK/jheappo/wiki
7 | */
8 |
9 | import java.io.DataInputStream;
10 | import java.io.IOException;
11 |
12 |
13 | public class HeapProfileHeader {
14 | private static String SUPPORTED_VERSIONS[] = {"JAVA PROFILE 1.0.1", "JAVA PROFILE 1.0.2"};
15 | private static int[] SUPPORTED_IDENIFIER_SIZE = {4, 8};
16 |
17 | private String heapDumpVersion;
18 | private int sizeOfIdentifiers = 0; /* u4 is unsigned 4 bytes.. which in this case is ok to assigned to signed int */
19 | private long millisecSinceEPOC;
20 |
21 | HeapProfileHeader() {
22 | }
23 |
24 | private String extractVersionString(DataInputStream buffer) throws IOException {
25 | char[] string = new char[1024];
26 | int pos = 0;
27 | int value;
28 | while ((value = buffer.read()) > 0)
29 | string[pos++] = (char) value;
30 | if (value < 0)
31 | throw new IOException("Unexpected EOF");
32 | return new String(string).trim();
33 | }
34 |
35 | public void extract(DataInputStream buffer) throws IOException {
36 | heapDumpVersion = extractVersionString(buffer);
37 | if (!(SUPPORTED_VERSIONS[0].equals(heapDumpVersion) || (SUPPORTED_VERSIONS[1]).equals(heapDumpVersion))) {
38 | throw new IOException(heapDumpVersion + " is not supported");
39 | }
40 | sizeOfIdentifiers = buffer.readInt();
41 | if (sizeOfIdentifiers != SUPPORTED_IDENIFIER_SIZE[1] && sizeOfIdentifiers != SUPPORTED_IDENIFIER_SIZE[0]) {
42 | throw new IOException("Unsupported identifier size " + sizeOfIdentifiers);
43 | }
44 | millisecSinceEPOC = buffer.readLong();
45 | }
46 |
47 | public String toString() {
48 | return heapDumpVersion + " : " + sizeOfIdentifiers + " : " + millisecSinceEPOC;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/HeapProfileRecord.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 | /*
4 | * Copyright (c) 2018 Kirk Pepperdine.
5 | * Licensed under https://github.com/AdoptOpenJDK/jheappo/blob/master/LICENSE
6 | * Instructions: https://github.com/AdoptOpenJDK/jheappo/wiki
7 | */
8 |
9 | public abstract class HeapProfileRecord {
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/HeapSummary.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 |
4 | public class HeapSummary extends HeapProfileRecord {
5 | public static final int TAG = 0x07;
6 |
7 | public HeapSummary(EncodedChunk body) {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/LoadClass.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 | /*
4 | * Copyright (c) 2018 Kirk Pepperdine.
5 | * Licensed under https://github.com/AdoptOpenJDK/jheappo/blob/master/LICENSE
6 | * Instructions: https://github.com/AdoptOpenJDK/jheappo/wiki
7 | */
8 |
9 | public class LoadClass extends HeapProfileRecord {
10 |
11 |
12 | public final static int TAG = 0x02;
13 |
14 | /*
15 | u4 | class serial number (always > 0)
16 | ID | class object ID
17 | u4 | stack trace serial number
18 | ID | class name string ID
19 | */
20 |
21 | private long classSerialNumber;
22 | private long classObjectID;
23 | private long stackTraceSerialNumber;
24 | private long classNameStringID;
25 |
26 | public LoadClass(EncodedChunk body) {
27 | classSerialNumber = body.extractU4();
28 | classObjectID = body.extractID();
29 | stackTraceSerialNumber = body.extractU4();
30 | classNameStringID = body.extractID();
31 | }
32 |
33 | public long getClassObjectID() {
34 | return classObjectID;
35 | }
36 |
37 | public long classSerialNumber() {
38 | return classSerialNumber;
39 | }
40 |
41 | public long stackTraceSerialNumber() {
42 | return stackTraceSerialNumber;
43 | }
44 |
45 | public long classNameStringID() {
46 | return classNameStringID;
47 | }
48 |
49 | public String toString() {
50 | return "Loaded -> " + classSerialNumber + ":" + classObjectID + ":" + stackTraceSerialNumber + ":" + classNameStringID;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/StackFrame.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 |
4 | /*
5 | * Copyright (c) 2018 Kirk Pepperdine.
6 | * Licensed under https://github.com/AdoptOpenJDK/jheappo/blob/master/LICENSE
7 | * Instructions: https://github.com/AdoptOpenJDK/jheappo/wiki
8 | */
9 |
10 |
11 | import org.adoptopenjdk.jheappo.io.HeapProfileRecord;
12 |
13 | /*
14 | ID | stack frame ID
15 | ID | method name string ID
16 | ID | method signature string ID
17 | ID | source file name string ID
18 | u4 | class serial number
19 | u4 | > 0 | line number
20 | | 0 | no line information available
21 | | -1 | unknown location
22 | | -2 | compiled method (Not implemented)
23 | | -3 | native method (Not implemented)
24 | */
25 |
26 | public class StackFrame extends HeapProfileRecord {
27 |
28 | public final static int TAG = 0x04;
29 |
30 | private long stackFrameID;
31 | private long methodNameStringID;
32 | private long methodSignatureStringID;
33 | private long sourceFileNameStringID;
34 | private long classSerialNumber;
35 |
36 | public StackFrame(EncodedChunk body) {
37 | stackFrameID = body.extractID();
38 | methodNameStringID = body.extractID();
39 | methodSignatureStringID = body.extractID();
40 | sourceFileNameStringID = body.extractID();
41 | classSerialNumber = body.extractID();
42 | }
43 |
44 | public String toString() {
45 | return "StackFrame --> " + stackFrameID + ":" + methodNameStringID + ":" + methodSignatureStringID + ":" + sourceFileNameStringID + ":" + classSerialNumber;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/StackTrace.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 | /*
4 | * Copyright (c) 2018 Kirk Pepperdine.
5 | * Licensed under https://github.com/AdoptOpenJDK/jheappo/blob/master/LICENSE
6 | * Instructions: https://github.com/AdoptOpenJDK/jheappo/wiki
7 | */
8 |
9 |
10 | import org.adoptopenjdk.jheappo.io.HeapProfileRecord;
11 |
12 | public class StackTrace extends HeapProfileRecord {
13 |
14 | public final static int TAG = 0x05;
15 |
16 | /*
17 | u4 | stack trace serial number
18 | u4 | thread serial number
19 | u4 | number of frames
20 | [ID]* | series of stack frame ID's
21 | */
22 |
23 | private int stackTraceSerialNumber;
24 | private int threadSerialNumber;
25 | private int numberOfFrames;
26 | private long[] stackFrameIDs;
27 |
28 | public StackTrace(EncodedChunk body) {
29 | stackTraceSerialNumber = body.extractU4();
30 | threadSerialNumber = body.extractU4();
31 | numberOfFrames = body.extractU4();
32 | stackFrameIDs = new long[numberOfFrames];
33 | for (int i = 0; i < numberOfFrames; i++) {
34 | stackFrameIDs[i] = body.extractID();
35 | }
36 | }
37 |
38 | public String toString() {
39 |
40 | return "StackTrace --> " + stackTraceSerialNumber + ":" + threadSerialNumber + ":" + numberOfFrames;
41 | }
42 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/StartThread.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 |
4 | public class StartThread extends HeapProfileRecord {
5 | public static final int TAG = 0x0A;
6 |
7 | public StartThread(EncodedChunk body) {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/UTF8StringSegment.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 | /*
4 | * Copyright (c) 2018 Kirk Pepperdine.
5 | * Licensed under https://github.com/AdoptOpenJDK/jheappo/blob/master/LICENSE
6 | * Instructions: https://github.com/AdoptOpenJDK/jheappo/wiki
7 | */
8 |
9 | import org.adoptopenjdk.jheappo.io.HeapProfileRecord;
10 | import org.adoptopenjdk.jheappo.objects.UTF8String;
11 |
12 | public class UTF8StringSegment extends HeapProfileRecord {
13 |
14 | /*
15 | ID | ID for this string
16 | [u1]* | UTF8 characters for string (NOT NULL terminated)
17 | */
18 |
19 | public final static int TAG = 0x01;
20 |
21 | private final EncodedChunk body;
22 |
23 | public UTF8StringSegment(EncodedChunk body) {
24 | this.body = body;
25 | }
26 |
27 | public UTF8String toUtf8String() {
28 | // defer UTF8 parsing
29 | return new UTF8String(body.copy());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/io/UnloadClass.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.io;
2 |
3 |
4 | public class UnloadClass extends HeapProfileRecord {
5 | public static final int TAG = 0x03;
6 |
7 | /*
8 | u4 | class serial number (always > 0)
9 | */
10 |
11 | private long classSerialNumber;
12 |
13 | public UnloadClass(EncodedChunk body) {
14 | classSerialNumber = body.extractU4();
15 | }
16 |
17 | public String toString() {
18 | return "Unloaded -> " + classSerialNumber;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/model/ArrayValue.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.model;
2 |
3 | import org.adoptopenjdk.jheappo.objects.BasicDataTypes;
4 |
5 |
6 | public class ArrayValue extends BasicDataTypeValue {
7 | public ArrayValue() {
8 | super(BasicDataTypes.ARRAY);
9 | }
10 |
11 | @Override
12 | public String toString() {
13 | return "Array";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/model/BasicDataTypeValue.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.model;
2 |
3 | import org.adoptopenjdk.jheappo.objects.BasicDataTypes;
4 |
5 |
6 | public class BasicDataTypeValue {
7 | private Object value;
8 | private BasicDataTypes type;
9 |
10 | public BasicDataTypeValue(BasicDataTypes type) {
11 | this.type = type;
12 | }
13 |
14 | public BasicDataTypeValue(Object value, BasicDataTypes type) {
15 | this.value = value;
16 | this.type = type;
17 | }
18 |
19 | public BasicDataTypes getType() {
20 | return type;
21 | }
22 |
23 | public Object getValue() {
24 | return this.value;
25 | }
26 |
27 | public String toString() {
28 |
29 | return value + " of type " + type.toString();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/core/src/main/java/org/adoptopenjdk/jheappo/model/BooleanValue.java:
--------------------------------------------------------------------------------
1 | package org.adoptopenjdk.jheappo.model;
2 |
3 | import org.adoptopenjdk.jheappo.objects.BasicDataTypes;
4 |
5 |
6 | public class BooleanValue extends PrimitiveValue