java - 成员字段位于 JVM 中的什么位置?
问题描述
public class MemoryTest {
final String fs = "final String"; //A
final int fi = 1; //A
String s = "Member String"; //A
int i = 2; //A
final static String fss = "final static String"; //B
final static int fsi = 3; //B
static String ss = "static String"; //C
static int si = 4; //C
public static void main(String args[]){
MemoryTest m = new MemoryTest();
}
}
[我的答案]
//A: 从类中创建对象时,通过引用方法区的常量池将其复制到对象中,并为创建的对象分配这些值。
=> 位置:堆
//B : 存在于方法区的常量池中,不复制到对象
=> 位置:方法区域的常量池
// C : 当执行引擎运行“static {}”时,方法区中的类变量会被引用到方法区中的一个常量池中。
=> location : 方法区的类变量
解决方案
//A: 从类中创建对象时,通过引用方法区的常量池将其复制到对象中,并为创建的对象分配这些值。
不正确。
您所说的常量池是类文件的一部分,运行程序1无法引用池中的值。解释器和 JIT 编译器在后台使用它们,但这在应用程序级别是不可见的。
常量池由类文件中的所有方法共享。它不属于任何方法领域。
在字符串文字和字符串值常量表达式的情况下,类文件常量池中的值用于创建String
对象2。然后将该对象interned
放入运行时字符串池,并添加到运行时描述符中。
请注意,字符串池与常量池不同。在现代 JVM 中,字符串池是常规堆中的数据结构。
=> 位置:堆
正确的。String
对象和MemoryTest
持有fs
, fi
,s
和变量的对象i
都在堆中;即这些变量都在堆中。
和s
变量fs
保存引用。i
和变量保存简单的fi
32 位整数值。他们没有提到任何东西。它们是……自给自足的。
//B : 存在于方法区的常量池中,不复制到对象
不正确;看上面。
情况有点复杂ffi
,该变量的值的使用可能会被字节码编译器内联到代码中。但是,该字段在运行时仍然存在,并且可以使用反射或调试代理访问。
=> 位置:方法区域的常量池
不正确。对象的位置String
在上面的字符串池中。fss
和变量位于类静态框架中,该fsi
框架也在堆中。
// C : 当执行引擎运行“static {}”时,方法区中的类变量会被引用到方法区中的一个常量池中。
不正确;看上面。(虽然si
不会被内联。)
=> location : 方法区的类变量
不正确;看上面。
1 - 好的,您可以编写应用程序代码来自己解析类文件。或者您可以(理论上)使用本机代码来查找 JVM 缓存常量池的位置并挖掘信息。只是不要。
2 - 这曾经是急切地完成的,但最近的 JVMString
在第一次使用字符串文字时会懒惰地创建对象。实际上可以编写一个测试来推断对象的创建时间。Jon Skeet 给我看了一次 :-)
推荐阅读
- agent - 应用程序被重定向到顶级领域,而不是在 Forgerock 中使用 Web 代理注册的领域
- flutter - 如何在 Flutter 中访问 AppBarTextField 的搜索按钮?
- wordpress - 为我的网站 Laravel + wordpress 使用自动平台优化
- ios - iPadOS mouse polling rate is too low. Only getting 60hz
- javascript - 尝试使用函数结果时出错,typeError: Cannot read property 'map' of undefined in React
- python - 如何根据时间间隔创建新列?
- rust - 如何将 Rust 代码编译为裸机 32 位 x86 (i686) 代码?我应该使用什么编译目标?
- reactjs - 创建自定义组件包装器
- docker - Vue Vite 无法连接到 docker 容器
- mongodb - MongoDB - 如何将 mongodb 归档文件转换为 JSON 格式