jvm是如何解析参数的
对于每个+XX参数(比如PrintGC),都会调用到arguments.cpp的parse_argument方法,然后jvm回去找之前定义过的Flag(大概有1120左右个FLAG,比如PrintGC),
也即是find_flag方法,如果找到了返回Null,否则返回一个bool值
具体处理在boolAtPut,根据查找结果返回true或者false,并且给指定flag设置值(避免每次都执行查找)
现在碰到的问题就是- XX: +DoEscapeAnalysis 这个参数,jvm报找不到
方法真正调用的地方
int JNICALL
JavaMain(void * _args)是最开始的方法,首先会create_jvm,然后创建一个新线程去loadMainClass
loadMain以后会执行方法
mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
"([Ljava/lang/String;)V");
来执行static方法,这个是一个JNI接口,具体内容如下:
JNI_ENTRY(jmethodID, jni_GetStaticMethodID(JNIEnv *env, jclass clazz,
const char *name, const char *sig))
JNIWrapper("GetStaticMethodID");
#ifndef USDT2
DTRACE_PROBE4(hotspot_jni, GetStaticMethodID__entry, env, clazz, name, sig);
#else /* USDT2 */
HOTSPOT_JNI_GETSTATICMETHODID_ENTRY(
env, (char *) clazz, (char *) name, (char *)sig);
#endif /* USDT2 */
jmethodID ret = get_method_id(env, clazz, name, sig, true, thread);
#ifndef USDT2
DTRACE_PROBE1(hotspot_jni, GetStaticMethodID__return, ret);
#else /* USDT2 */
HOTSPOT_JNI_GETSTATICMETHODID_RETURN(
(uintptr_t) ret);
#endif /* USDT2 */
return ret;
JNI_END
注意进入到get_method_id方法:
其中sig就是方法的签名字符串,然后生成的klass对象会lookup_method去寻找对应签名的方法
Method* lookup_method(Symbol* name, Symbol* signature) const {
return uncached_lookup_method(name, signature, find_overpass);
}
而真正执行方法的是:
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
然后这个方法会调用:
jni_invoke_static(env, &jvalue, NULL, JNI_STATIC, methodID, &ap, CHECK);
然后
static void jni_invoke_static(JNIEnv *env, JavaValue* result, jobject receiver, JNICallType call_type, jmethodID method_id, JNI_ArgumentPusher *args, TRAPS) {
methodHandle method(THREAD, Method::resolve_jmethod_id(method_id));
// Create object to hold arguments for the JavaCall, and associate it with
// the jni parser
ResourceMark rm(THREAD);
int number_of_parameters = method->size_of_parameters();
JavaCallArguments java_args(number_of_parameters);
args->set_java_argument_object(&java_args);
assert(method->is_static(), "method should be static");
// Fill out JavaCallArguments object
args->iterate( Fingerprinter(method).fingerprint() );
// Initialize result type
result->set_type(args->get_ret_type());
// Invoke the method. Result is returned as oop.
JavaCalls::call(result, method, &java_args, CHECK);
实际调用的是JavaCalls的call,进一步调用call_helper
call_helper里面真正docall的方法就是:
StubRoutines::call_stub()(
(address)&link,
// (intptr_t*)&(result->_value), // see NOTE above (compiler problem)
result_val_address, // see NOTE above (compiler problem)
result_type,
method(),
entry_point,
args->parameters(),
args->size_of_parameters(),
CHECK
);
在stubGeneratir_zero的方法里面
这个方法会setup栈,并且最终进入
Interpreter::invoke_method(method, entry_point, THREAD);
需要注意的是invoke_method,是不是反射的invoke方法呢? 看起来很像:
实际调用到entry_point(这就是一个方法的入口点)的invoke,结果后面就是linkResolver.cpp? 咋还要解析????? 调用栈如下,其实最终调到的是call_virtual
结果call_virtual也是调call,艹:
void JavaCalls::call_virtual(JavaValue* result, KlassHandle spec_klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) {
CallInfo callinfo;
Handle receiver = args->receiver();
KlassHandle recvrKlass(THREAD, receiver.is_null() ? (Klass*)NULL : receiver->klass());
LinkResolver::resolve_virtual_call(
callinfo, receiver, recvrKlass, spec_klass, name, signature,
KlassHandle(), false, true, CHECK);
methodHandle method = callinfo.selected_method();
assert(method.not_null(), "should have thrown exception");
// Invoke the method
JavaCalls::call(result, method, args, CHECK);
}
然后执行字节码
JvmtiHideSingleStepping jhss(thread);
LinkResolver::resolve_invoke(info, receiver, pool,
get_index_u2_cpcache(thread, bytecode), bytecode, CHECK);
i
那么问题来了,在parseClassFile的时候也会进到这个方法,靠!
关键还是,这个Method结构体,我看不懂,全tm是字符。。。
现在把
初始化java system的时候是如下:
build方法用来构建栈帧,后面就是执行字节码了,关于栈和栈帧,参考滑动验证页面
关注一下stack_words = max_stack =1,这个是方法的最大栈深度,如果构造器方法,其实max_stack至少是2,因为要调用父类Object的初始化方法(invokesepcial指令)
max_locals就是这个方法的局部变量总数
参数参见 Chapter 4. The class File Format
有一个
locals = stack->sp() + (method->max_locals() - 1);
有点好奇为啥locals就是sp+ max_locals,难道metho最开始就是local局部变量?
然后就是while循环执行字节码:
走进了ByteCode的run方法
其中有个bcp
其实就是
// 获取解释器当前的(B)yte (C)ode (P)ointer,也就是当前指令地址,以指针表达
static address bcp(JavaThread *thread) {
return last_frame(thread).interpreter_frame_bcp();
}
然后因为是方法,会走到method_entry里面:
set_do_not_unlock方法,好像是为了synchronize字段的
如果是synchronize方法,会特殊处理 ,后面会释放unlock
接下来goto run:
先是pc自增,然后会根据指令,来获取索引,
然后CALL_VM的时候,会进入入口点
接下来进入resolve_invoke
后面就到了LinkResolve的resolve_static
resolve_static_call会根据method来生成一个KlassHandle实例,
然后会调用set_static方法:
set_common方法:
问题是,这到底解析了个啥? 我也不知道
不过method的signature是个Symbol对象
InstanceKlass:每个java类都对应一个InstanceKlass ,存储类的元信息,具体布局看下图
可以看到InstanceKlass里面有annotation,fields, 其实下面还有methods,是个数组
接下来进入cache_entry方法:
最后会返回一个ConstantPoolCacheEntry指针:
首先会bias锁校验,看是不是biased_lock_pattern,一般来说是1(unlocked_value)
enum { locked_value = 0,
unlocked_value = 1,
monitor_value = 2,
marked_value = 3,
biased_lock_pattern = 5
};
跑完以后会,走到代码 goto run,然后又开始增加pc计数,如下图:
run的时候会根据opcode执行指定操作,如下:
关于java的mirror,可看上图及下图,上图可以看出,静态方法其实就是取对应的java mirror,也就是class实例,如果非静态方法,就取LOCAL_OBJECT(0)
第6.1篇-方法解析之Method与ConstMethod介绍 - 鸠摩(马智) - 博客园
jvm的method
TLAB 区别于栈内存分配,是为每个线程分配一个很小的私有堆,默认开启
浅堆和深堆,实际的大小
浅堆可以理解对象引用的大小,基本都很小,比如一个int就8个字节,一个String24个字节
深堆就是gc以后能释放的空间
偏向锁最后两位固定为01
cinit是class的初始化(比如初始化静态变量),init是实例的初始化(比如new A())
final变量是准备阶段(准备阶段就是分配内存,并且初始化为默认值,类似于memset)就赋值,非final就是在初始化阶段赋值
解析就是:将类接口、宇段和方法的符号引用转为直接引用
初始化:就是调用clinit方法(会执行非final静态变量和static代码块的语句) 多线程可能会死锁
8.2.2轻量级锁 281对应的源码看一下,8.2.2后面也没看
8.3看了
第10章看完了
5.5看到了5.5.4
第11章11.5及往后都看完了,除了11.5.4
热替换,就是不断轮询,看class文件有没有更新的过程
双亲委派的弊端,就是父类无法访问子类加载的类,作为一种补充,可以通过SPI机制,以及Thread的currentThread的getContextLoader,这样父类就能访问子类加载的类了
另一种打破双亲委派机制的方法是: 重写loadClass方法,大概率也要同时重写loadClass内部的findClass方法,参考:
ClassLoader笔记_newbaby2012的博客-CSDN博客
Arthas学习
jad 反编译
dashboard 看板
thread <pid> 查看耗费cpu的代码在哪一行
锁分离,是一种减小锁粒度的特例,比如LinkedBlockingQueue,就是入队
和出队两个锁,而不是锁整个队列,读写就有更好的并发
Full GC 自适应策略
Full GC (Ergonomics) 产生的原因_→思的博客-CSDN博客_ergonomics jvm
G1收集器总结
G1是Garbage First Garbage Collector的简称,其实会把堆分成很多个小的区域:S代表survivor,E代表Eden(伊甸园,人类开始居住的地方,也即对象刚开始所在的地方),O代表Old老年代,G就代表Garbage(垃圾占比比较高的区域,优先收集G)
那么G类区域是如何生成的呢?我猜是并发标记周期的时候,给标上的G(猜对了hhh),而这些G型区域会被记录在Collection Set中
G1收集的4个阶段:新生代GC, 并发标记周期,混合收集(年轻代,老年代都会回收),FULL GC
并发标记周期是G1最重要的一个阶段,分很多,但我不想写,截个图吧