天天看點

JVMTI開發教程之帶引用關系的class柱狀圖

我們來看下上一節中的顯示效果和本節例子的最終顯示效果的異同:

JVMTI開發教程之帶引用關系的class柱狀圖

上圖是上一節中例子中的顯示效果。

JVMTI開發教程之帶引用關系的class柱狀圖

上圖是本節例子中的最終顯示效果。可以看到,我們不僅可以獲知某個class的執行個體數量,執行個體的總占用空間,以及class name。還能觀察到class及其整棵引用樹上的class的執行個體數量,空間,name等。

<a></a>

本節沒有用到任何新的jvmti函數。不過比起第二節,會基于更多函數的入參(上一節中,許多入參都是閑置)來實作本例子中的功能。

上一節中,我們了解到,通過followreference的jvmtiheapreferencecallback可以得到jvmti函數從heap root開始掃描其下存活對象的引用關系樹,這個過程非常類似gc。

為了實作本例的功能,我們需要利用這個函數,記錄它回報的引用關系,并加工就能得到一顆完整的引用關系樹。

回調函數中,我們需要關注的入參是 class_tag和referer_class_tag,後者代表引用目前對象的對象所屬class的标簽。通過這個标簽,我們可以從ci_map中擷取真實的classinfo. 具體實作詳見下文的代碼片段。 本例的難點是如何記錄和構造這顆引用關系樹。 筆者的實作方式比較簡單,在classinfo結構中,維護一個單向連結清單。

在記錄引用關系的同時,我們還需要注意:

1,遞歸引用需要排除。比如 a類成員變量也是a類自身。

2,java.lang.class不需要計算到引用關系中。我們知道任何一個class都有引用它。忽略它可以提高存儲和計算效率。

3,節點的祖先不應該出現重複的節點。

比如 a-&gt;b-&gt;c-&gt;a,這裡第四層的a就不應該出現在引用關系樹上。否則會重複列印(a後面又是 b-&gt;c-&gt;a-&gt;b-&gt;c-&gt;a…)。

實作代碼片段:

這份源碼與上一節中的源碼非常類似,主要是 heapfrcallback 函數裡添加了引用關系的記錄。列印結果的程式片段處,添加遞歸列印樹的函數。此外就是添加了新的資料結構 referrer 。

下面是完整的源碼,copy,另存為,編譯即可運作。

jvmti tutorial - jmap -histo include reference.

*

created on: 2011-3-3

author: kenwu

*/

#include

using namespace std;

class referrer {

public:

referrer() {

cls_id = 0;

next = null;

}

~referrer() {

delete next;

int cls_id;

referrer *next;

};

class classinfo {

classinfo() {

name = null;

instance_cnt = 0;

instance_size = 0;

cls_obj_flag = 0;

referrer = null;

~classinfo() {

free(name);

delete referrer;

char name;

int instance_cnt;

long instance_size;

int cls_obj_flag;

referrer referrer;

classinfo *ci_map;

jvmtienv jvmti;

int seq;

int total_cls_size;

int depth = 5;

/**

解析class符号,抽取出class name并格式化。

@return class name

/

char getclassname(jclass cls) {

int xl = 0;

char sig;

char data;

jvmti-&gt;getclasssignature(cls, &amp;sig, null);

if (sig) {

return data;

jint jnicall heapfrcallback(jvmtiheapreferencekind reference_kind,

const jvmtiheapreferenceinfo reference_info, jlong class_tag,

jlong referrer_class_tag, jlong size, jlong tag_ptr,

jlong referrer_tag_ptr, jint length, void user_data) {

// clean duplicate

int act_obj = 0;

if (tag_ptr == 0) { tag_ptr = ++seq;

act_obj = 1;

} else if (*tag_ptr cls_obj_flag == 0) {

ci-&gt;cls_obj_flag = 1;

jint jnicall untagcallback(jlong class_tag, jlong size, jlong tag_ptr,

jint length, void user_data) {

*tag_ptr = 0;

return jvmti_visit_objects;

referrer get_max(referrer head) {

referrer *max = head;

while (null != head) {

if (ci_map[head-&gt;cls_id]-&gt;instance_size

&gt; ci_map[max-&gt;cls_id]-&gt;instance_size) {

max = head;

head = head-&gt;next;

return max;

void sort_referrers(referrer head) {

referrer node = head, *tmp;

int value;

while (null != node) {

tmp = get_max(node);

if (node != tmp) {

value = node-&gt;cls_id;

node-&gt;cls_id = tmp-&gt;cls_id;

tmp-&gt;cls_id = value;

node = node-&gt;next;

bool allontree(referrer *ci, set ref_tree) {

while (null != ci) {

if (ref_tree.find(ci-&gt;cls_id) == ref_tree.end()) {

return false;

ci = ci-&gt;next;

return true;

void printrefinfo(classinfo ci, int level, set ref_tree,

set grade_format) {

if (++level &gt;= depth)

return;

ref_tree.insert(ci-&gt;cls_id);

referrer referrer = ci-&gt;referrer;

sort_referrers(referrer);

int max = 0;

while (referrer != null) {

classinfo *c1 = ci_map[referrer-&gt;cls_id];

if (max++ cls_id) == ref_tree.end()) {

string strbuf(“”);

jniexport jint jnicall agent_onattach(javavm jvm, char options,

void reserved) {

/*

jniexport void jnicall agent_onunload(javavm *vm) {

// nothing to do

本文來源于"阿裡中間件團隊播客",原文發表時間" 2011-03-17 "