【06】JVM是如何实现反射的?

news2024/9/21 0:43:05

为了保证框架的可扩展性,往往借助 Java 的反射机制,根据配置文件来加载不同的类。Spring 框架的依赖反转(IoC),便是依赖于反射机制。

反射调用的实现

这里主要是以【方法的反射调用】来进行剖析

public final class Method extends Executable {
  ...
  public Object invoke(Object obj, Object... args) throws ... {
    ... // 权限检查
    MethodAccessor ma = methodAccessor;
    if (ma == null) {
      ma = acquireMethodAccessor();
    }
    return ma.invoke(obj, args);
  }
}

Mehton.invoke内部是通过MethodAccessor来进行真正的实现,MethodAccessor是一个接口,它的具体实现有两个:

  • 本地实现:通过本地方法来实现反射调用
  • 委托实现:委派模式实现

每个Method实例第一次反射调用都会生成一个委派实现,所委派的具体实现是一个本地实现。

// v0 版本
import java.lang.reflect.Method;

public class Test {
  public static void target(int i) {
    new Exception("#" + i).printStackTrace();
  }

  public static void main(String[] args) throws Exception {
    Class<?> klass = Class.forName("Test");
    Method method = klass.getMethod("target", int.class);
    method.invoke(null, 0);
  }
}

# 不同版本的输出略有不同,这里我使用了 Java 10。
$ java Test
java.lang.Exception: #0
        at Test.target(Test.java:5)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl .invoke0(Native Method)
        //本地实现
       at java.base/jdk.internal.reflect.NativeMethodAccessorImpl. .invoke(NativeMethodAccessorImpl.java:62)
        //委托实现
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.i .invoke(DelegatingMethodAccessorImpl.java:43)
 
        java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at Test.main(Test.java:131

Method.invoke的执行序列图如下:
在这里插入图片描述

注意到这里通过代理类DelegatingMethodAccessorImpl作为一个中间层来对NativeMethodAccessorImpl进行代理,目的是能够在本地实现与动态实现(Java的反射调用机制还设立了另一种动态生成字节码的实现,直接使用invoke指令来调用目标方法)进行一个切换。

动态实现和本地实现相比,其运行效率要快上 20 倍 这是因为动态实现无需经过 Java 到 C++ 再到 Java的切换,但由于生成字节码十分耗时,仅调用一次的话,反而是本地实现要快3到4倍。考虑到许多反射调用仅会执行一次,Java 虚拟机设置了一个阈值15(Dsun.reflect.inflationThreshold控制)
当某个反射调用的调用次数在 15 之下时,采用本地实现;当达到15时,便开始动态生成字节码,并将委派实现的委派对象切换至动态实现,这个过程我们称之为 Inflation

下面看下代码

// v1 版本
import java.lang.reflect.Method;

public class Test {
  public static void target(int i) {
    new Exception("#" + i).printStackTrace();
  }

  public static void main(String[] args) throws Exception {
    Class<?> klass = Class.forName("Test");
    Method method = klass.getMethod("target", int.class);
    for (int i = 0; i < 20; i++) {
      method.invoke(null, i);
    }
  }
}

# 使用 -verbose:class 打印加载的类
$ java -verbose:class Test
...
java.lang.Exception: #14
        at Test.target(Test.java:5)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl .invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl .invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl .invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at Test.main(Test.java:12)
[0.158s][info][class,load] ...
...
[0.160s][info][class,load]
//这里触发动态实现的生成,加载了GeneratedMethodAccessor1类
jdk.internal.reflect.GeneratedMethodAccessor1 source: __JVM_DefineClass__
java.lang.Exception: #15
       at Test.target(Test.java:5)
       at java.base/jdk.internal.reflect.NativeMethodAccessorImpl .invoke0(Native Method)
       at java.base/jdk.internal.reflect.NativeMethodAccessorImpl .invoke(NativeMethodAccessorImpl.java:62)
       at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl .invoke(DelegatingMethodAccessorImpl.java:43)
       at java.base/java.lang.reflect.Method.invoke(Method.java:564)
       at Test.main(Test.java:12)
java.lang.Exception: #16
       at Test.target(Test.java:5)
       //直接通过GeneratedMethodAccessor1类来进行invoke
       at jdk.internal.reflect.GeneratedMethodAccessor1 .invoke(Unknown Source)
       at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl .invoke(DelegatingMethodAccessorImpl.java:43)
       at java.base/java.lang.reflect.Method.invoke(Method.java:564)
       at Test.main(Test.java:12)
...

反射调用的开销

方法的反射调用会带来不少的性能开销,原因主要是三个

  • 变长参数方法导致的Object数据
  • 基本类型的自动装拆箱
  • 方法内联

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2037572.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cocosUI多分辨率适配

需求&#xff1a;由于各个设备的分辨率和尺寸并不一样&#xff0c;所以需要一套适配系统去很好的针对不同的设备分辨率或尺寸进行适配&#xff0c;以给玩家一个很好的游戏体验。 目前的主流适配方案 目前&#xff0c;针对不同设备的适配&#xff0c;主流的方案通常包括以下几种…

OpenHarmony4.1上初体验rust

OpenHarmony4.1上初体验rust 前言一、准备工作二、初步调研三、初步尝试运行测试demo 四、尝试构建自己的hello world五、与C、C的交互总结 前言 由于后续可能要做rust基于OpenHarmony的开发工作&#xff0c;于是先开始一些调研性的工作&#xff0c;rust了解的内容可以参考该文…

雷达气象学(6)——径向速度图分析

文章目录 6.1 速度场分析基础6.1.1 速度图分析的基本方法6.1.2 练习&#xff1a;整层为均匀西风6.1.3 练习&#xff1a;风向随高度顺转 6.2 水平均匀风场的典型图像6.3 典型天气系统的判别6.3.1 锋面&#xff08;切变线&#xff09;系统6.3.1.1 冷锋&#xff08;冷式切变线&…

苹果是如何成为一家以产品力驱动的公司

最近在看苹果的HIG&#xff08;开发者指南&#xff09;文档&#xff0c;深刻的体会到设计/产品能力对于用户的重要性&#xff0c;为什么苹果会有“设计可以改变一切”“产品即营销”这样的理念&#xff0c;而苹果也的的确确成为了少数以产品驱动的科技公司。 文档本身有六部分…

【数据结构详解】——归并排序(动图详解)

目录 &#x1f552; 1. 归并排序&#x1f558; 1.1 递归实现&#x1f558; 1.2 非递归实现 &#x1f552; 1. 归并排序 &#x1f4a1; 算法思想&#xff1a;归并排序是建立在归并操作上的一种有效的排序算法&#xff0c;该算法是采用分治法的一个非常典型的应用。将已有序的子…

蓝牙资讯|AirPods Pro 2推送最新开发者版固件,支持点头摇头控制Siri

苹果面向开发者推送了 AirPods Pro 2 的最新固件更新&#xff0c;版本号为 7A5266c。这并非一次常规更新是为即将在秋季发布的 iOS 18 系统做准备。 根据官方信息&#xff0c;新固件将为 AirPods Pro 2 引入一系列新功能&#xff0c;包括点头或摇头控制 Siri、增强嘈杂环境下…

Visual Studio Code 使用Git详细教程

再集成之前请确保已经安装Visual Studio Code 和Git&#xff0c;并且可以找到Git文件地址。如果找不到可以在系统环境变量里面看一眼之前的配置-需要找到Git下面的cmd目录&#xff0c;一会配置使用。 打开 Visual Studio Code找到设置根据图片指引 1.找到左下角设置按钮 2.展开…

支付宝沙箱模拟支付的实现

目录 1.登录支付宝开发平台 2.使用沙箱模拟支付 3.后端代码 4.前端代码 现在几乎所有应用或者网站都需要接入支付接口&#xff0c;因为一个产品最终目的还是要赚钱&#xff0c;所以我们今天就使用支付宝提供的模拟支付的接口来实现这个功能。 1.登录支付宝开发平台 支付宝…

deepin V23前瞻丨deepin V23与飞腾腾锐D3000完成适配,持续丰富deepin操作系统硬件生态

查看原文 近日&#xff0c;自主核心芯片研发飞腾公司宣布与deepin V23完成适配&#xff0c;包含飞腾新一代桌面CPU飞腾腾锐D3000、FT-2000/64、桌面芯片飞腾腾锐D2000等多款产品&#xff0c;为用户带来更智能、安全、稳定的使用体验。 飞腾腾锐D3000集成8个飞腾自主研发的新一…

微服务-分布式事务-seata

1. 事务 事务(TRANSACTION)是作为单个逻辑工作单元执行的一系列SQL操作&#xff0c;这些操作作为一个整体一起向系统提交&#xff0c;要么执行&#xff0c;要么都不执行 1.1 ACID事务的特点 原子性&#xff1a;针对同一事务&#xff0c;要么都完成&#xff0c;要么都不完成 一致…

实例讲解Jmeter参数化的四种方式

JMeter的四种参数化方式包括&#xff1a; 1.用户参数&#xff08;UserParameters&#xff09;&#xff1a;适用于参数取值范围很小的时候使用 2.函数助手&#xff08;FunctionHelper&#xff09;&#xff1a;可作为其他参数化方式的补充项&#xff0c;如&#xff1a;随机数生成…

使用RestHighLevelClient进行Elasticsearch Function Score查询

简介 Function Score查询在Elasticsearch中是一个强大的工具&#xff0c;它允许我们根据一个或多个函数来调整查询结果的相关性得分。这使得我们可以基于某些条件对搜索结果进行更精细的控制。本文将介绍如何在Java应用程序中使用Elasticsearch的RestHighLevelClient执行Funct…

城市夜景车水马龙视频素材去哪里找?

在这个数字化与视觉化日益融合的时代&#xff0c;城市夜景已成为吸引观众眼球的热门视频主题。无论是个人爱好者还是企业&#xff0c;都致力于通过展示繁华都市的夜晚来俘获观众的心。今天&#xff0c;我将为您介绍几个优秀的视频素材网站&#xff0c;帮助您获取高质量的城市夜…

在小红书用AI做搞笑日常图文号,单号软广赚3000+!

今天&#xff0c;当我在小红书上刷案例时&#xff0c;突然眼前一亮&#xff0c;发现了一些以沙雕日常为主题的手绘插画图文账号。这些账号的笔记点赞量高得惊人&#xff0c;每篇都有上千的点赞&#xff0c;而且植入的软广告报价也是高得吓人。 像上图这个账号&#xff0c;它只发…

MetaLLM大语言模型文本生成算法分析报告

一、算法安全与监测 算法安全 信息内容安全方面&#xff0c;MetaLLM算法必须确保生成的文本不包含有害信息&#xff0c;如不当言论、歧视性内容等。这需要在训练数据中进行严格的筛选&#xff0c;并在模型设计时加入过滤机制。信息源安全则关注于训练数据的质量和多样性&…

【sgCreateAPIFunction】自定义小工具:敏捷开发→自动化生成API接口方法代码片段脚本(接口方法代码生成工具)

sgCreateAPIFunction源码 <template><!-- 前往https://blog.csdn.net/qq_37860634/article/details/141159084 查看使用说明 --><div :class"$options.name"><div class"sg-head">接口方法生成工具<el-dropdown:show-timeou…

vue2+OpenLayers 地图上添加渐变色(6)

渐变还有些问题需要晚上 引入 import sxs from "/views/json/sx.json"; import sx from "/views/json/sx1.json"; import GeoJSON from "ol/format/GeoJSON"; import Polygon, { fromExtent } from "ol/geom/Polygon"; import Linear…

文件上传漏洞-防御

防御文件上传的方法各种各样 1、限制文件上传的类型&#xff08;不让上传php等脚本类文件、只允许上传图片&#xff09; 2、给上传的文件重命名&#xff0c;让攻击者找不到自己传的文件在哪 3、限制文件上传大小 4、压缩上传文件 5、把上传的文件存储到文件服务器或者OSS平…

uniapp获取头像文件(二进制文件显示图片)

一、描述 由于在获取头像文件过程中&#xff0c;传递参数之后&#xff0c;请求成功了&#xff0c;但是后端给我返回了一串二进制数据流&#xff0c;傻傻的我&#xff0c;以为是乱码&#xff0c;跑去问后端大哥&#xff0c;人家跟我说这不是二进制吗&#xff0c;突然就觉得自己傻…

引领端侧多模态新时代:MiniCPM-V 2.6重磅登场

前沿科技速递&#x1f680; 在人工智能领域&#xff0c;每一次技术的进步都伴随着参数规模的提升和计算力的突破。然而&#xff0c;面壁智能公司最新推出的MiniCPM-V 2.6端侧多模态模型&#xff0c;却以相对“小巧”的8B参数量级&#xff0c;打破了传统思维&#xff0c;实现了端…