首页 > 基础资料 博客日记

几分钟了解下java虚拟机--02

2025-06-18 00:00:02基础资料围观8

这篇文章介绍了几分钟了解下java虚拟机--02,分享给大家做个参考,收藏Java资料网收获更多编程知识

几分钟应该看不完,私密马赛, 俺是标题党
既然来了, 看看吧, 球球你了

Java类加载器

类的生命周期和加载过程

  • 加载 加载所有的.class文件/jar文件/网络流 →字节流 (JVM 与java.lang.classLoader协作)

存储于Metaspace/Method Area

  • 校验 确保 class 文件里的字节流信息符合当前虚拟机的要求,不会危害虚拟机的安全
  • 准备 设置变量默认值 分配内存
  • 解析 解析常量池符号引用转换为直接引用,主要有以下四种:类或接口的解析、字段解析、类方法解析、接口方法解析 链接相关参数, 方法索引(为后续初始化和运行提供直接引用)
  • 初始化 执行类构造器 <clinit> 方法 初始化

类加载时机


类加载机制


JVM方法调用

方法于JVM构成 : 类名, 方法名, 方法描述符{参数类型, 返回参数类型}

JVM方法查询

子类的静态方法会隐藏(注意与重写区分)父类中的同名、同描述符的静态方法 Interface 同理

虚方法调用

  • 虚拟方法表 链接时建立class的虚方法(非static, final)表

分离invokinterfaceinvokevirtual原因

class A
    1: method1
    2: method2
class B extends A
    1: method1
    2: method2
    3: method3
class B extends A implements X
    1: method1
    2: method2
    3: method3
    4: methodX
class C implements X
    1: methodC
    2: methodX

  • 内联缓存

         *-只是缓存并非内联(嵌入内部)*
    

执行过程中,如果碰到已缓存的类型,内联缓存便会直接调用该类型所对应的目标方法。


  • 劣化为超多态状态

JVM处理异常

异常基本概念

因为异常总是动态的, 实时的, 所以我们总是new exception()



如何捕获异常

每个method都会维护一张 Exception table

  Exception table:
    from  to target type
      0   3     6   Class java/lang/Exception  

Java 7 的 Suppressed 异常以及语法糖

try {
    in0 = new FileInputStream(new File("in0.txt"));
    ...
    try {
      in1 = new FileInputStream(new File("in1.txt"));
      ...
      try {
        in2 = new FileInputStream(new File("in2.txt"));
        ...
      } finally {
        if (in2 != null) in2.close();
      }
    } finally {
      if (in1 != null) in1.close();
    }
  } finally {
    if (in0 != null) in0.close();
try (Foo foo0 = new Foo("Foo0");          // try-with-resources语法糖优化后
         Foo foo1 = new Foo("Foo1");      // 该语法糖下自动使用suppressed异常
         Foo foo2 = new Foo("Foo2")) {
      throw new RuntimeException("Initial");
    }

**suppressed异常**允许将一个异常附于另一个异常之上。因此,抛出的异常可以附带多个异常的信息

JVM实现反射机制

依赖于 JVM 的类加载器和运行时数据结构(如方法表、字段表)

怎么用

应用

  • IDE 每当我们敲入点号时,IDE 便会根据点号前的内容,动态展示可以访问的字段或者方法
  • Java调试器 在调试过程中枚举某一对象所有字段的值
  • Spring framework IOC

Method.invoke

本地实现, 委派实现, 动态实现(均由MethodAccessor抽象)

getMethod会形成一份class内方法的的拷贝 -避免在热点代码中使用getMethod

取消委派实现, 关闭检查时目标方法的权限可以小幅度提升性能

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);
  }
}
  • 本地实现
// 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)
   **↑   
 invoke**     at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at Test.main(Test.java:131
  • 委派实现

作为invoke实现的中间件

选择method invoke本地实现还是动态实现

  • 动态实现(纯java字节码, 无需重新从java→c++→java)

优势在于避免了 JNI ( java native interface )的切换开销,但它的缺点是生成字节码耗时

// 动态实现的伪代码,这里只列举了关键的调用逻辑,其实它还包括调用者检测、参数检测的字节码。
package jdk.internal.reflect;
 
public class GeneratedMethodAccessor1 extends ... {
  @Overrides    
  public Object invoke(Object obj, Object[] args) throws ... {
    Test.target((int) args[0]);
    return null;
  }
}
Method method1 = Test.class.getMethod("target", int.class);
Method method2 = Test.class.getMethod("target", int.class);

JVM实现invokedynamic

方法句柄(Method Handle)

class Foo {
  private static void bar(Object o) {
    ..
  }
  public static Lookup lookup() {
    return MethodHandles.lookup();
  }
}
 
// 获取方法句柄的不同方式
MethodHandles.Lookup l = Foo.lookup(); // 具备 Foo 类的访问权限
Method m = Foo.class.getDeclaredMethod("bar", Object.class);
MethodHandle mh0 = l.unreflect(m);
 
MethodType t = MethodType.methodType(void.class, Object.class);
MethodHandle mh1 = l.findStatic(Foo.class, "bar", t);

方法句柄的操作


如果你看完了, 非常感谢你对我付出的认可🥰🥰🥰😘😘😘


文章来源:https://www.cnblogs.com/many-bucket/p/18933753
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云