JVM中的成员字段在哪里?

时间:2019-03-16 05:54:34

标签: java jvm-hotspot

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:方法区域的类变量

ByteCode Analysis

1 个答案:

答案 0 :(得分:2)

  

// A:从类创建对象时,会将其复制到   对象通过引用常量池的方法区域,并创建   对象分配了这些值。

不正确。

  1. 您正在谈论的常量池是类文件的一部分,并且运行程序 1 不能引用该池中的值。解释器和JIT编译器在后台使用它们,但是在应用程序级别看不见。

  2. 常量池由类文件中的所有方法共享。它不属于任何方法领域。

对于字符串文字和字符串值常量表达式,类文件常量池中的值用于创建String对象 2 。然后将该对象interned放入运行时字符串池,并添加到运行时描述符。

请注意,字符串池与常量池不同。在现代JVM中,字符串池是常规堆中的数据结构。

  

=>位置:堆

正确。 String对象和保存MemoryTestfsfis变量的i对象都在堆中;即这些变量都在堆中。

sfs变量保存引用。 ifi变量包含简单的32位整数值。他们没有提及任何东西。他们...是独立的。

  

// B:存在于方法区域的常量池中,未复制到对象

不正确;见上文。

ffi的情况有点复杂,字节码编译器可以将该变量的值内联到代码中。但是,该字段在运行时仍然存在,可以使用反射或调试代理进行访问。

  

=>位置:方法区域的常量池

不正确。 String对象的位置在字符串池中,如上所述。 fssfsi变量在静态框架类中,该框架也在堆中。

  

// C:当执行引擎运行“ static {}”时,方法区域中的类变量将通过引用方法区域中的常量池来分配。

不正确;往上看。 (尽管si不会被内联。)

  

=> location:方法区域的类变量

不正确;见上文。


1-好的,您可以编写自己解析类文件的应用程序代码。或者,您可以(理论上)使用本机代码来查找JVM将常量池缓存到何处并挖掘出信息。只是不要。

2-以前很想这样做,但是最近的JVM第一次使用字符串文字时就懒惰地创建了String对象。实际上可以编写一个测试来推断对象的创建时间。乔恩·斯基特(Jon Skeet)给我看了一次