JVM 符号引用(Symbolic References)

本文深入探讨Java中的符号引用概念,解释其在直接引用不可行时的作用。同时,详细介绍了JNI字段、类及方法描述符的规则,帮助理解如何通过符号引用唯一标识类、字段或方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


符号引用


  • 什么是符号引用?在说符号引用之前我们先来看看直接引用,直接引用是什么,比如就是你拥有你所需要数据的地址值,可以直接根据地址值获取到数据。但是 java语言是解释性的语言,然后由于总总原因(我也不知道对不对的原因)在某些时刻有些东西的直接地址还并不存在,是无法使用直接引用。这时候就可以用到符号引用了。
  • 符号引用:符号引用是一个字符串,它给出了被引用的内容的名字并且可能会包含一些其他关于这个被引用项的信息——这些信息必须足以唯一的识别一个类、字段、方法。这样,对于其他类的符号引用必须给出类的全名。对于其他类的字段,必须给出类名、字段名以及字段描述符。对于其他类的方法的引用必须给出类名、方法名以及方法的描述符。这样我们就能根据符号引用锁定唯一的类,方法或字段了。

JNI字段描述符


  • JNI字段描述符是类描述符,方法描述符,字段描述的具体的实现规则,下面我将一一介绍。
类描述符

  • 例:
类:Java.lang.String
对应描述符:Ljava/lang/String;
  • 类描述符的规则是以L开头,其后跟着该类的全限定名,并将其中中的 “.” 改为 “/” ,最后分号“;”结束(只有 类描述符需要以分号结束好像,基本类型的不需要)。
  • 再补上其他基本类型的符号(由于基本类型不存在全限定名,只需要一个符号就可以表达该基本类型)
java类型符号
booleanZ
byteB
charC
shortS
intI
longJ
floatF
doubleD
voidV
字段描述符

  • 好像类描述符也是字段描述符,有点晕~。我们确定一个字段,只需要字段描述符和字段名两部分。那好像除了字段名,字段描述符只需要描述类型就可以了,所以类描述符好像等价于了字段描述符。
  • 例:
int num=3;
字段描述符:I;
字段名:num
  • 但是字段还有数组类型,数组的描述规则如下
String[][] num=null;
字段描述符:[[Ljava/lang/String;
字段名:num
  • 数组类型只需要原描述符在前面加一个[,如果是二维数组就加[[,以此类推。
方法描述符
  • 例1:
String test();
方法描述符:()Ljava/lang/String;
方法名:test
  • 例2:
long test(int i, Object c);
方法描述符:(ILjava/lang/Object;)J
方法名:test
  • 例3:

void test(byte[] bytes);
方法描述符:([B)V
方法名:test
  • 三个例子很清晰的就能看明白了,方法描述符就是“()”和参数与返回值的字段描述符的组合,组合规则是:
(第一个参数的字段描述符第二个参数的字段描述符.....)返回类型的描述符
### JVM 方法区中运行时常量池的工作机制与作用 #### 1. 运行时常量池的概念 运行时常量池(Runtime Constant Pool)是方法区的一部分,它用于存储类文件中的常量信息。这些信息包括但不限于字面量(literals)、符号引用symbolic references),以及通过某些方式动态生成的常量[^2]。 #### 2. 运行时常量池的作用 运行时常量池的主要作用在于支持程序运行时所需的各类常量资源。具体来说: - 它保存了由编译器生成的各种字面量和符号引用。 - 提供了一个可扩展的空间,允许在运行期间动态加入新创建的常量,比如通过 `String.intern()` 方法产生的字符串实例[^3]。 #### 3. 动态性特点 与其他类型的常量池相比,运行时常量池的一个显著特点是其 **动态性**。这意味着不仅限于预先定义好的常量可以存入其中,在程序执行过程中还可以新增加一些未预料到的数据项。例如当调用 `String.intern()` 函数时,如果该字符串尚未存在于字符串常量池,则会将其添加进去。 #### 4. 存储内容 运行时常量池所包含的具体内容有以下几个方面: - 字面量:如整数、浮点数等基本数据类型值; - 符号引用:指向其他对象或者方法的名字及其描述符; - 动态生成的新常量:像上述提到过的经由`intern()`操作引入的字符串实例。 #### 5. 可能引发的问题——内存溢出 由于运行时常量池位于方法区内,因此它的大小受到整个方法区域容量的影响。一旦超出设定界限就会抛出OutOfMemoryError错误提示。这种情况可能发生在频繁加载卸载大量临时性的class文件或是滥用 intern() 方法导致过多独一无二的字符串驻留等情况之下[^4]。 ```java // 示例代码展示如何可能导致 OOM 错误 public classOOMExample { public static void main(String[] args){ Set<String> set = new HashSet<>(); try{ while(true){ String str = UUID.randomUUID().toString(); set.add(str.intern()); } }catch(OutOfMemoryError e){ System.err.println("Out of Memory Error!"); } } } ``` 此段代码不断生成随机UUID并将它们转换成interned形式存放到HashSet里头,最终因为持续增加的独特字符串填满运行时常量池而导致 OutOfMemoryError 发生。 #### 总结 综上所述,JVM 中的方法区内的运行时常量池是一个非常重要的组件,负责管理应用程序运行所需的一系列静态及动态生成的常量资料。了解其工作机制对于优化性能、预防潜在风险具有重要意义。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值