JVMTI开发教程之带引用关系的class柱状图

    xiaoxiao2023-12-20  190

    我们来看下上一节中的显示效果和本节例子的最终显示效果的异同:

    Class统计信息柱状图 上图是上一节中例子中的显示效果。带引用关系的Class统计信息柱状图 上图是本节例子中的最终显示效果。可以看到,我们不仅可以获知某个class的实例数量,实例的总占用空间,以及class name。还能观察到class及其整棵引用树上的class的实例数量,空间,name等。

    实现思路

    本节没有用到任何新的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->B->C->A,这里第四层的A就不应该出现在引用关系树上。否则会重复打印(A后面又是 B->C->A->B->C->A…)。

    实现代码片段:

    完整源码

    这份源码与上一节中的源码非常类似,主要是 heapFRCallback 函数里添加了引用关系的记录。打印结果的程序片段处,添加递归打印树的函数。此外就是添加了新的数据结构 Referrer 。

    下面是完整的源码,copy,另存为,编译即可运行。

    JVMTI Tutorial - jmap -histo include reference. *Created on: 2011-3-3Author: kenwu */ #include #include #include #include #include #include #include #include #include

    using namespace std;

    class Referrer { public: Referrer() { cls_id = 0; next = NULL; } ~Referrer() { cls_id = 0; delete next; } int cls_id; Referrer *next; };

    class ClassInfo { public: ClassInfo() { name = NULL; cls_id = 0; instance_cnt = 0; instance_size = 0; cls_obj_flag = 0; referrer = NULL; } ~ClassInfo() { cls_id = 0; free(name); instance_cnt = 0; instance_size = 0; cls_obj_flag = 0; delete referrer; } int cls_id; 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->GetClassSignature(cls, &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->cls_obj_flag = 1; act_obj = 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->cls_id]->instance_size > ci_map[max->cls_id]->instance_size) { max = head; } head = head->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->cls_id; node->cls_id = tmp->cls_id; tmp->cls_id = value; } node = node->next; } }

    bool allOnTree(Referrer *ci, set ref_tree) { while (NULL != ci) { if (ref_tree.find(ci->cls_id) == ref_tree.end()) { return false; } ci = ci->next; } return true; }

    void printRefInfo(ClassInfo ci, int level, set ref_tree, set grade_format) { if (++level >= depth) return; ref_tree.insert(ci->cls_id); Referrer referrer = ci->referrer; sort_referrers(referrer); int max = 0; while (referrer != NULL) { ClassInfo *c1 = ci_map[referrer->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 "

    相关资源:敏捷开发V1.0.pptx
    最新回复(0)