经验:
选择通过测试类来查看代码逻辑时,要认真选择一个简单的测试类,配置少的类开始,循序渐进,而不是随便选一个类,不然会一直花时间在排错上
哎,面试携程,被面试官说学得不成体系,现在看看hotspot源码,看看是个啥玩意
monitorenter指令,在interpreter里面的runtime,
什么不变,不变的是人性
不变的是底层,是操作系统,汇编,C,C++
核心是创建内存模型,创建栈帧,以及实现字节码指令
字节码指令相关的源码,在java的hotspot的interpreter里面
流程: classLoader 加载指定文件位置,读取对应的字节码文件,转换成byte[]
对字节码进行解析
通过AppClassLoader
ObjectMonitor构造函数:
ObjectMonitor() {
_header = NULL;
_count = 0;
_waiters = 0,
_recursions = 0; //锁重入次数
_object = NULL;
_owner = NULL; //拥有该对象的线程?
_WaitSet = NULL;
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ; //单项列表
FreeNext = NULL ;
_EntryList = NULL ;
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
_previous_owner_tid = 0;
}
有关栈的一些代码
stack_size -= 2 * page_size();
所以每个线程的栈空间,是两页? 不是的,
if (max_size > 0) {
_initial_thread_stack_size = MIN2(max_size, stack_size);
} else {
// Accept the rlimit max, but if stack is unlimited then it will be huge, so
// clamp it at 8MB as we do on Solaris
_initial_thread_stack_size = MIN2(stack_size, 8*M);
}
如果没有指定的话,最大初始栈空间为8*M
线程栈的location,是由/proc/self/stat 这个文件决定的吗
if (find_vma((address)stack_start, &low, &high)) {
// success, "high" is the true stack top. (ignore "low", because initial
// thread stack grows on demand, its real bottom is high - RLIMIT_STACK.)
stack_top = (uintptr_t)high;
} else {
// failed, likely because /proc/self/maps does not exist
warning("Can't detect initial thread stack location - find_vma failed");
// best effort: stack_start is normally within a few pages below the real
// stack top, use it as stack top, and reduce stack size so we won't put
// guard page outside stack.
stack_top = stack_start;
stack_size -= 16 * page_size();
}
上述代码,表明栈其实是从栈顶开始按需分配的,栈底其实不需要指明
JVM 模型
hotspot源文件布局
share是最有趣的,而vm是最相关,最重要的,对于jvm而言
标红的,是我们最需要看的,也是字节码文件、解析最重要的,these are good places to start
这些OOPS在JVM内部有着不同的用途,例如,instanceOopDesc表示类实例,arrayOopDesc表示数组。也就是说,当我们使用new创建一个Java对象实例的时候,JVM会创建一个instanceOopDesc对象来表示这个Java对象。同理,当我们使用new创建一个Java数组实例的时候,JVM会创建一个arrayOopDesc对象来表示这个数组对象。
TOS top-of-stack 是个啥?
下面的示意图,我感觉是分配栈帧,invokeX以后分配一个栈帧
Thread
WatcherThread应该是守护线程?
entry method through interpreter,走到entry points,