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:方法区域的类变量
答案 0 :(得分:2)
// 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-以前很想这样做,但是最近的JVM第一次使用字符串文字时就懒惰地创建了String
对象。实际上可以编写一个测试来推断对象的创建时间。乔恩·斯基特(Jon Skeet)给我看了一次