当前位置:   article > 正文

JVM之类的热替换原理解读,中软国际java面试

JVM之类的热替换原理解读,中软国际java面试

}

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);

}

}

eventHandlerClassFileLoadHook()在收到消息后,会调用transformClassFile():

void

transformClassFile( JPLISAgent * agent,

JNIEnv * jnienv,

jobject loaderObject,

const char* name,

jclass classBeingRedefined,

jobject protectionDomain,

jint class_data_len,

const unsigned char* class_data,

jint* new_class_data_len,

unsigned char** new_class_data,

jboolean is_retransformer) {

transformedBufferObject = (*jnienv)->CallObjectMethod(

jnienv,

agent->mInstrumentationImpl,

agent->mTransform,

moduleObject,

loaderObject,

classNameStringObject,

classBeingRedefined,

protectionDomain,

classFileBufferObject,

is_retransformer);

}

这里会利用JNI调用 java 层InstrumentationImpl的transform(),你看,我们又绕到Java层了:

private byte[] transform( Module module,

ClassLoader loader,

String classname,

Class<?> classBeingRedefined,

ProtectionDomain protectionDomain,

byte[] classfileBuffer,

boolean isRetransformer) {

TransformerManager mgr = isRetransformer?

mRetransfomableTransformerManager :

mTransformerManager;

// module is null when not a class load or when loading a class in an

// unnamed module and this is the first type to be loaded in the package.

if (module == null) {

if (classBeingRedefined != null) {

module = classBeingRedefined.getModule();

} else {

module = (loader == null) ? jdk.internal.loader.BootLoader.getUnnamedModule()
loader.getUnnamedModule();

}

}

if (mgr == null) {

return null; // no manager, no transform

} else {

return mgr.transform( module,

loader,

classname,

classBeingRedefined,

protectionDomain,

classfileBuffer);

}

}

上面主要就是调用TransformerManager的transform():

public byte[] transform( Module module,

ClassLoader loader,

String classname,

Class<?> classBeingRedefined,

ProtectionDomain protectionDomain,

byte[] classfileBuffer) {

boolean someoneTouchedTheBytecode = false;

TransformerInfo[] transformerList = getSnapshotTransformerList();

byte[] bufferToUse = classfileBuffer;

// order matters, gotta run 'em in the order they were added

for ( int x = 0; x < transformerList.length; x++ ) {

TransformerInfo transformerInfo = transformerList[x];

ClassFileTransformer transformer = transformerInfo.transformer();

byte[] transformedBytes = null;

try {

transformedBytes = transformer.transform( module,

loader,

classname,

classBeingRedefined,

protectionDomain,

bufferToUse);

}

catch (Throwable t) {

// don’t let any one transformer mess it up for the others.

// This is where we need to put some logging. What should go here? FIXME

}

if ( transformedBytes != null ) {

someoneTouchedTheBytecode = true;

bufferToUse = transformedBytes;

}

}

// if someone modified it, return the modified buffer.

// otherwise return null to mean “no transforms occurred”

byte [] result;

if ( someoneTouchedTheBytecode ) {

result = bufferToUse;

}

else {

result = null;

}

return result;

}

看到这儿,大家还记得我们开始的时候,会将我们自定义的ClassFileTransformer对象注册到TransformerManager中吗?这里终于派上用场了,TransformerManager的transform()方法会遍历它的注册数组,调用每个ClassFileTransformer对象的transform()方法,并将我们修改后的类字节码返回,返回后的字节码最终又回到了上面JVM层的transformClassFile()中,并最终交还给给class_file_load_hook 消息的发送方。

让我们回到消息的发送方:check_shared_class_file_load_hook()中去看看:

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

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

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

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

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

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

如何快速更新自己的技术积累?

  • 在现有的项目里,深挖技术,比如用到netty可以把相关底层代码和要点都看起来。
  • 如果不知道目前的努力方向,就看自己的领导或公司里技术强的人在学什么。
  • 知道努力方向后不知道该怎么学,就到处去找相关资料然后练习。
  • 学习以后不知道有没有学成,则可以通过面试去检验。

我个人觉得面试也像是一场全新的征程,失败和胜利都是平常之事。所以,劝各位不要因为面试失败而灰心、丧失斗志。也不要因为面试通过而沾沾自喜,等待你的将是更美好的未来,继续加油!

以上面试专题的答小编案整理成面试文档了,文档里有答案详解,以及其他一些大厂面试题目

八年CRUD,疫情备战三个月,三面头条、四面阿里拿offer面经分享

八年CRUD,疫情备战三个月,三面头条、四面阿里拿offer面经分享

会持续更新**

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-Hj0NxeB9-1711759120610)]

如何快速更新自己的技术积累?

  • 在现有的项目里,深挖技术,比如用到netty可以把相关底层代码和要点都看起来。
  • 如果不知道目前的努力方向,就看自己的领导或公司里技术强的人在学什么。
  • 知道努力方向后不知道该怎么学,就到处去找相关资料然后练习。
  • 学习以后不知道有没有学成,则可以通过面试去检验。

我个人觉得面试也像是一场全新的征程,失败和胜利都是平常之事。所以,劝各位不要因为面试失败而灰心、丧失斗志。也不要因为面试通过而沾沾自喜,等待你的将是更美好的未来,继续加油!

以上面试专题的答小编案整理成面试文档了,文档里有答案详解,以及其他一些大厂面试题目

[外链图片转存中…(img-L75qtjoT-1711759120611)]

[外链图片转存中…(img-CoUp3WSR-1711759120612)]

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/450796
推荐阅读
相关标签
  

闽ICP备14008679号