JVM之类的热替换原理解读,2024年最新java语法基础实验

}

目前已经有很多文章讲具体使用方法了,大家可以Google下,我这里先介绍两篇:

原理探究

========

热替换的核心就在于Instrumentation的两个方法:

void addTransformer(ClassFileTransformer transformer, boolean canRetransform);

void retransformClasses(Class<?>… classes) throws UnmodifiableClassException;

addTransformer()用来注册类的修改器;

retransformClasses()会让类重新加载,从而使得注册的类修改器能够重新修改类的字节码。

下面让我们细细讲讲这两个函数:

3.1: addTransformer()

addTransformer的实现在InstrumentationImpl中:

//sun.instrument.InstrumentationImpl

public synchronized void addTransformer(ClassFileTransformer transformer, boolean canRetransform) {

mRetransfomableTransformerManager.addTransformer(transformer);

}

上面代码省略了一些,可见我们的ClassFileTransformer又被添加到了TransformerManager中,让我们跟进去看看:

//sun.instrument.TransformerManager

public synchronized void addTransformer( ClassFileTransformer transformer) {

TransformerInfo[] oldList = mTransformerList;

TransformerInfo[] newList = new TransformerInfo[oldList.length + 1];

System.arraycopy( oldList,

0,

newList,

0,

oldList.length);

newList[oldList.length] = new TransformerInfo(transformer);

mTransformerList = newList;

}

ClassFileTransformer对象这次被放入了TransformerManager的一个数组中。

OK,注册完毕,很简单对不对?下面我们再来看下稍微复杂点的retransformClasses()吧。

3.2: retransformClasses()

这个方法的实现是个Native方法。

private native void retransformClasses0(long var1, Class<?>[] var3);

很多同学看到Native方法就头疼,不要急,Native方法也是人写的,不过是一段文本而已。我们来看下他的具体实现吧:

// src/java.instrument/share/native/libinstrument/InstrumentationImplNativeMethods.c

JNIEXPORT void JNICALL

Java_sun_instrument_InstrumentationImpl_retransformClasses0

(JNIEnv * jnienv, jobject implThis, jlong agent, jobjectArray classes) {

retransformClasses(jnienv, (JPLISAgent*)(intptr_t)agent, classes);

}

retransformClasses()最后会调用到 jvmtiEnv.cpp中的RetransformClasses

// src/hotspot/share/prims/jvmtiEnv.cpp

jvmtiError

JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) {

int index;

JavaThread* current_thread = JavaThread::current();

ResourceMark rm(current_thread);

jvmtiClassDefinition* class_definitions =

NEW_RESOURCE_ARRAY(jvmtiClassDefinition, class_count);

for (index = 0; index < class_count; index++) {

HandleMark hm(current_thread);

jclass jcls = classes[index];

oop k_mirror = JNIHandles::resolve_external_guard(jcls);

Klass* klass = java_lang_Class::as_Klass(k_mirror);

jint status = klass->jvmti_class_status();

if (status & (JVMTI_CLASS_STATUS_ERROR)) {

return JVMTI_ERROR_INVALID_CLASS;

}

InstanceKlass* ik = InstanceKlass::cast(klass);

if (ik->get_cached_class_file_bytes() == NULL) {

JvmtiClassFileReconstituter reconstituter(ik);

if (reconstituter.get_error() != JVMTI_ERROR_NONE) {

return reconstituter.get_error();

}

class_definitions[index].class_byte_count = (jint)reconstituter.class_file_size();

class_definitions[index].class_bytes = (unsigned char*)

reconstituter.class_file_bytes();

} else {

// it is cached, get it from the cache

class_definitions[index].class_byte_count = ik->get_cached_class_file_len();

class_definitions[index].class_bytes = ik->get_cached_class_file_bytes();

}

class_definitions[index].klass = jcls;

}

VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_retransform);

VMThread::execute(&op);

return (op.check_error());

}

上面这段主要干了两件事:

(1) 根据java层的Class对象,找到JVM层的类实例InstanceKlass,并获取类的字节码,存放在class_definitions数组中。因为可以一次替换多个类,所以这里加了一个循环体,遍历每个要修改的类。

(2) 调用VMThread::execute(&op),进入下一步。

VMThread::execute(&op) 中会调用到 VM_RedefineClasses::doit_prologue(),最终调用到VM_RedefineClasses::load_new_class_versions():

jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) {

InstanceKlass* the_class = get_ik(_class_defs[i].klass);

Symbol* the_class_sym = the_class->name();

ClassFileStream st((u1*)_class_defs[i].class_bytes,

_class_defs[i].class_byte_count,

VM_RedefineClasses”,

ClassFileStream::verify);

Handle the_class_loader(THREAD, the_class->class_loader());

Handle protection_domain(THREAD, the_class->protection_domain());

state->set_class_being_redefined(the_class, _class_load_kind);

InstanceKlass* scratch_class = SystemDictionary::parse_stream(

the_class_sym,

the_class_loader,

protection_domain,

&st,

}

上面这个方法调用了parse_stream(),从文件流中解析类,最终触发类的重新加载:

InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,

Handle class_loader,

Handle protection_domain, TRAPS) {

InstanceKlass* new_ik = KlassFactory::check_shared_class_file_load_hook(

ik, class_name, class_loader, protection_domain, CHECK_NULL);

if (new_ik != NULL) {

return new_ik;

}

return ik;

}

这里又调用了KlassFactory::check_shared_class_file_load_hook(),看名字就知道是个hook方法,它会调用post_class_file_load_hook(),利用JvmtiClassFileLoadHookPoster来通知类修改器进行类的修改。

消息的处理者为:eventHandlerClassFileLoadHook():

void JNICALL

eventHandlerClassFileLoadHook( jvmtiEnv * jvmtienv,

JNIEnv * jnienv,

jclass class_being_redefined,

jobject loader,

const char* name,

jobject protectionDomain,

jint class_data_len,

const unsigned char* class_data,

jint* new_class_data_len,

unsigned char** new_class_data) {

JPLISEnvironment * environment = NULL;

environment = getJPLISEnvironment(jvmtienv);

/* if something is internally inconsistent (no agent), just silently return without touching the buffer */

if ( environment != NULL ) {

jthrowable outstandingException = preserveThrowable(jnienv);

transformClassFile( environment->mAgent,

jnienv,

loader,

name,

class_being_redefined,

protectionDomain,

class_data_len,

class_data,

new_class_data_len,

new_class_data,

environment->mIsRetransformer);

restoreThrowable(jnienv, outstandingException);

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

总结

互联网大厂比较喜欢的人才特点:对技术有热情,强硬的技术基础实力;主动,善于团队协作,善于总结思考。无论是哪家公司,都很重视高并发高可用技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。

**另外本人还整理收藏了2021年多家公司面试知识点以及各种技术点整理 **

下面有部分截图希望能对大家有所帮助。

在这里插入图片描述

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

1712740583179)]

总结

互联网大厂比较喜欢的人才特点:对技术有热情,强硬的技术基础实力;主动,善于团队协作,善于总结思考。无论是哪家公司,都很重视高并发高可用技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。

**另外本人还整理收藏了2021年多家公司面试知识点以及各种技术点整理 **

下面有部分截图希望能对大家有所帮助。

[外链图片转存中…(img-ZyIV9B3H-1712740583180)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-labzf2Io-1712740583181)]

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值