《JVM G1源码分析和调优》 —2.6.3 JVM本地方法栈中的对象
2.6.3 JVM本地方法栈中的对象
上节介绍本地方法栈是如何管理和链接对象的。每一个Java线程都私有一个句柄区_handle_area来存储其运行过程中创建的临时对象,这个句柄区是随着Java线程的栈帧变化的,我们看一下HandleMark是如何管理的。HandleArea的作用上一节已经介绍过了,这里我们先看一下它们的结构图(如图2-2所示),然后再通过代码演示如何管理句柄。
图2-2 句柄结构图
Java线程每调用一个Java方法就会创建一个对应HandleMark来保存已分配的对象句柄,然后等调用返回后即行恢复,代码如下所示:
hotspot/src/share/vm/runtime/javaCalls.cpp
JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArguments*
args, TRAPS) {
……
{
HandleMark hm(thread);
所以当Java线程运行一段时间之后,通过HandleMark构建的对象识别链如图2-3所示:
图2-3 本地方法栈对象的管理
这里Chunk的管理是动态变化的,第一个Chunk可能为256或者1024个字节,每一个Chunk都有一个额外空间,主要是调用malloc时会有一段额外的信息,比如地址的长度等,在32位机器上一般为20个字节,所以每一个Chunk都会比最大值少5个OOP对象。另外,一般的Chunk块通常为32KB。最后还需要提一点的就是,Handle
Mark通常都是分配在线程栈中,也意味着无需额外的管理,只需要找到HandleMark就能找到哪些对象是存活的。我们来看一个简单的例子,看看如何遍历堆空间。
下面这个代码片段是为了输出堆空间里面的对象,例如我们执行jmap命令来获取堆空间对象的时候最终会调用到VM_HeapDumper::do_thread()来遍历所有的对象。通过下面的代码我们能非常清楚地看到,如果JavaThread执行的是Java代码,则直接通过StackValueCollection访问局部变量,如果执行的是本地代码,线程则通过active_handles()访问句柄而访问对象。
hotspot/src/share/vm/services/heapDumper.cpp
int VM_HeapDumper::do_thread(JavaThread* java_thread, u4 thread_serial_num) {
JNILocalsDumper blk(writer(), thread_serial_num);
oop threadObj = java_thread->threadObj();
int stack_depth = 0;
if (java_thread->has_last_Java_frame()) {
Thread* current_thread = Thread::current();
ResourceMark rm(current_thread);
HandleMark hm(current_thread);
RegisterMap reg_map(java_thread);
frame f = java_thread->last_frame();
vframe* vf = vframe::new_vframe(&f, ®_map, java_thread);
frame* last_entry_frame = NULL;
int extra_frames = 0;
if (java_thread == _oome_thread && _oome_constructor != NULL) {
extra_frames++;
}
while (vf != NULL) {
blk.set_frame_number(stack_depth);
if (vf->is_java_frame()) {
// Java线程栈,包括(interpreted, compiled, ...)
javaVFrame *jvf = javaVFrame::cast(vf);
if (!(jvf->method()->is_native())) {
StackValueCollection* locals = jvf->locals();
for (int slot=0; slot<locals->size(); slot++) {
if (locals->at(slot)->type() == T_OBJECT) {
oop o = locals->obj_at(slot)();
if (o != NULL) {
writer()->write_u1(HPROF_GC_ROOT_JAVA_FRAME);
writer()->write_objectID(o);
writer()->write_u4(thread_serial_num);
writer()->write_u4((u4) (stack_depth + extra_frames));
}
}
}
} else {
// 本地方法栈
if (stack_depth == 0) {
java_thread->active_handles()->oops_do(&blk);
} else {
if (last_entry_frame != NULL) {
last_entry_frame->entry_frame_call_wrapper()->handles()->
oops_do(&blk);
}
}
}
stack_depth++;
last_entry_frame = NULL;
} else {
frame* fr = vf->frame_pointer();
assert(fr != NULL, "sanity check");
if (fr->is_entry_frame()) {
last_entry_frame = fr;
}
}
vf = vf->sender();
}
} else {
java_thread->active_handles()->oops_do(&blk);
}
return stack_depth;
}
- 点赞
- 收藏
- 关注作者
评论(0)