当前位置: 首页 > 知识库问答 >
问题:

JVM、常量池、堆和地址

广乐邦
2023-03-14

如果我在Jasmin assembly中创建一个新项目,然后将其存储,我会按照指令aload进行操作,因为它是一个地址:

    new Object
    dup
    invokespecial.....
    astore_3 ; load the object reference into local variable 3

现在,如果我想从常量池中保存一个字符串...我会用ldc创建它,然后用aload保存它:

    ldc "Great string"
    astore_3 ; save the reference to the actual string in the constant pool

现在...这些地址是否在相同的形式和相同的字节数上?因为我使用相同的指令来加载和存储这些项目,JVM必须能够区分属于常量池的地址和堆中的地址?

在检查字节码时,在我的例子中,常量池中的实际地址似乎只是一个1字节的索引(我猜常量池的主要引用也保存在某个地方)。。。现在我知道这是对常量池中som UTF8数据的引用,但这是实际字符串所在的位置,还是只是对其他地方的字节数组的引用?检查堆中“新对象”的地址我还没能做到。。。。。基本上,我需要弄清楚这两个内存区域如何使用相同形式的指令,以及JVM如何决定地址是常量池中的偏移量还是堆中的对象?

共有2个答案

阴福
2023-03-14

首先,整个字节码格式只是虚拟机提供的抽象。它不一定与运行时代码或内存的实际表示有任何相似之处。

其次,html" target="_blank">常量池是一个最多包含65,535个条目的表,使用16位索引。由于用小索引和类别1类型索引常量池是一项如此常见的任务,因此有一条专门的速记指令——ldc。

ldc指令使用单字节索引,因此只能用于前255个条目。如果你想访问上面的条目,你需要使用双字节形式ldc_w。这种情况与其他速记指令类似,比如aload_3 vs aload 3 vs wide aload 3。

再说一遍,这都是一种抽象。实际上,VM会将常量池转换为更友好的内部格式,并可能将指向其运行时位置的实际指针编译为代码。但这只是一种可能的实现。

商勇
2023-03-14

JVM在中解释的字节码不一定与在中编写的字节码相同。类文件。许多JVM在不同的执行阶段执行所谓的字节码重写。

HotSpot JVM也是如此。当类初始化时,HotSpot会重写引用到恒定池中String项的ldc字节码,其中包含JVM特定的fast_aldc字节码,该字节码引用CP缓存中的对象(即java.lang.String实例)。当此类fast_aldc字节码首次执行时,JVM会解析常量池项,在Java堆中创建String,并用对该String的引用填充CP缓存。在进一步执行相同的字节码时,JVM将立即从CP缓存中获取引用,并将其推送到Java堆栈。

在解释ldc字节码(或其重写形式)之后,堆栈顶部将包含对Java堆中对象的有效引用。newbytecode也会产生同样的引用。因此,没有必要区分引用类型。

这就是解释器的工作原理。当然,在方法被JIT编译后,就不再有字节码、常量池引用等了。所有这些都只是抽象。只是个模特。

 类似资料:
  • 问题内容: 我知道常量池的概念以及JVM用于处理字符串文字的字符串常量池。但是我不知道JVM使用哪种类型的内存来存储String常量文字。堆栈还是堆?由于它的文字不与任何实例相关联,因此我假定它将存储在堆栈中。但是,如果没有任何实例引用该文字,则必须通过GC运行来收集文字(如果我错了,请纠正我),那么如果将其存储在堆栈中,该如何处理? 问题答案: 从技术上来说,答案都不是。根据Java虚拟机规范,

  • 将在字符串常量池和堆中为以下代码创建多少个对象: 据我所知,所有的文本都是在字符串常量池中创建的,但是字符串concat操作符在内部使用StringBuffer来追加字符串,那么堆中也会创建一个对象吗?

  • 在爪哇 使用新运算符创建的对象将存储在堆内存中 我正在运行下面的代码来检查hashcode。 代码的输出是 这两个对象都是使用新运算符和字符串文字创建的,并相应地存储在不同的位置堆内存和字符串常量池中。那么内存地址是如何相同的。 如果我错了,请解释一下这个概念

  • 根据以下链接,java堆栈框架包含本地变量、操作数堆栈和当前类常量池引用。http://blog.jamesdbloom.com/JVMInternals.html 同样来自Oracle“JVM结构”第2.6节。3.“动态链接-每个帧(§2.6)包含对当前方法类型的运行时常量池(§2.5.5)的引用,以支持方法代码的动态链接。” 我还读到堆中的对象也有一个指向类数据的指针/引用。https://w

  • 在Java 7或更低版本中,如果使用以下语法创建字符串 根据此链接,每当我们创建一个字符串对象时,都会创建两个对象,即堆区域中的一个和字符串常量池中的一个,并且字符串对象引用始终指向堆区域对象,如下所示。 如果我们创建另一个与 具有相同值的String对象,内存表示将是什么 这会在堆中创建另一个具有相同值的对象吗? 还是只会创建引用字符串常量池到堆中的对象?

  • 如这些问题中所述:问题1 在以下情况下,JVM将创建一个新的字符串对象,而不是使用字符串池中的现有对象: 然而,在阅读了下面两个类似的陈述之后,我有一个疑问。 从SCJP准备书: 当编译器遇到字符串文字时,它会检查池中是否已经存在相同的字符串。如果找到匹配项,对新文本的引用将指向现有的String,并且不会创建新的String文本对象。 来自JavaRanch: 在本例中,由于关键字“new”,我