欲立則先破,想要弄清楚 hprof 是如何記錄咱們的類,對象所佔內存大小,以及引用鏈等,則先要破解出 hprof 的文件協議及內容。即 hprof 到底寫入了什麼?dom
同其餘類型文件,如Bitmap,Hprof 也有本身的文件的協議。其包括了 hprof head 和 hprof body 兩部分。head 部分主要包括版本,索引等,而 body 則存儲了類,對象,stack trace 等。貌似又是一個套路。spa
主要寫入了文件的版本描述及版本號,當前爲固定的以'/0'結尾的字串,ID標識的size,寫入時間戳。對象
19 | 4 | 8 |
"JAVA PROFILE 1.0.3/0" | indentify size | time stamp |
寫入了當前所用到全部的字符串,包括類名,常量等。這裏的TAG,以及其餘數據的 TAG 很重要。解析 Hprof 文件協議時,就是用 TAG 來區分的索引
string 的 TAG 定義爲 0x01ip
1 | 4 | 4 | 4 | strlen(string content) |
tag | time stamp | length | id | string content |
tag | time stamp | length | id | string content |
tag | time stamp | length | id | string content |
...... | ...... | ...... | ..... | ...... |
class 的 TAG 定義爲 0x02內存
1 | 4 | 4 | 4 | 4 | 4 | 4 |
tag | time stamp | length | class serial number | class object id | stack trace serial number | class name string idci |
...... | ..... | ..... | ..... | ...... | ...... | ...... |
stack trace 的 TAG 定義爲 0x05。實際取出來是空,即 num frames 爲 0element
1 | 4 | 4 | 4 | 4 | 4 |
tag | time stamp | length | serial number | thread serial number | num frames |
Body 部分,以一行爲劃分,每一行包括全部的 heap dump類型,以及該 heap dump下的子類型rem
1 | 4 | 4 |
tag(0x0C,HEAP_DUMP) | time stamp | length |
tag(0x1C,HEAP_DUMP_SEGMENT) | time stamp | length |
下面的 string id 對應的 string table 中的 string id字符串
1 | 4 | ||||
0xff(ROOT_UNKNOWN) | string id | [RootType.UNKNOW] | |||
1 | 4 | 4 | |||
0x01(ROOT_JNI_GLOBAL) | string id | jni global id | [RootType.NATIVE_STATIC] | ||
1 | 4 | 4 | 4 | ||
0x02(ROOT_JNI_LOCAL) | string id | thread serial number | stack frame number | ||
1 | 4 | 4 | 4 | ||
0x03(ROOT_JAVA_FRAME) | string id | thread serial number | stack frame number | ||
1 | 4 | 4 | |||
0x04(ROOT_NATIVE_STACK) | string id | thread serial number | |||
1 | 4 | ||||
0x05(ROOT_STICKY_CLASS) | string id | [RootType.SYSTEM_CLASS] | |||
1 | 4 | 4 | |||
0x06(ROOT_THREAD_BLOCK) | string id | thread serial number | |||
1 | 4 | ||||
0x07(ROOT_MONITOR_USED) | string id | [RootType.BUSY_MONITOR] | |||
1 | 4 | 4 | 4 | ||
0x08(ROOT_THREAD_OBJECT) | string id | thread serial number | stack frame number | ||
1 | 4 | ||||
0x20(ROOT_CLASS_DUMP) | string id | 有點複雜,在下面單獨列出來 | |||
1 | 4 | 4 | 4 | 4 | |
0x21(ROOT_INSTANCE_DUMP) | string id | stack id | class id | remaining(skip) | |
1 | 4 | 4 | 4 | 4 | |
0x22(ROOT_OBJECT_ARRAY_DUMP) | string id | stack id | num elements | class id | 4 * num elements(skip) |
1 | 4 | 4 | 4 | 1 | |
0x23(ROOT_PRIMITIVE_ARRAY_DUMP) | string id | stack id | num elements | primitive type | 4 * num elements(skip) |
1 | |||||
0xc3(ROOT_PRIMITIVE_ARRAY_NODATA) | 暫時表示錯誤類型 | ||||
1 | 4 | 4 | |||
0xfe(ROOT_HEAP_DUMP_INFO) | heap id | heap name id(string id) | |||
1 | 4 | ||||
0x89(ROOT_INTERNED_STRING) | string id | [RootType.INTERNED_STRING] | |||
1 | 4 | ||||
0x8a(ROOT_FINALIZING) | string id | [RootType.FINALIZING] | |||
1 | 4 | ||||
0x8b(ROOT_DEBUGGER) | string id | [RootType.DEBUGGER] | |||
1 | 4 | ||||
0x8c(ROOT_REFERENCE_CLEANUP) | string id | [RootType.REFERENCE_CLEANUP] | |||
1 | 4 | ||||
0x8d(ROOT_VM_INTERNAL) | string id | [RootType.VM_INTERNAL] | |||
1 | 4 | 4 | 4 | ||
0x8e(ROOT_JNI_MONITOR) | string id | thread serial number | stack frame number | ||
1 | 4 | ||||
0x90(ROOT_UNREACHABLE) | string id | [RootType.UNREACHABLE] |
0x20(ROOT_CLASS_DUMP) | 1 |
id | 4 |
stack serial number | 4 |
super class id | 4 |
class loader id | 4 |
signeres id | 4 |
protection domain id | 4 |
reserved | 4 |
reserved | 4 |
instance size | 4 |
const pool num entries | 2 |
2 * num entries | |
static fields num entries | 2 |
static fields | static fields num entries * (static fields),下面會再單獨列出來 |
instance fields num entries | 2 |
instance fields | instance fields num entries * (instance fields) |
4 | 1 | 4 |
static fields id | static fields type | type size |
4 | 1 |
instance id | instance type |