在Java中,原始静态变量和静态函数存储在哪里?

3
public Class A {
    public static String s = "s";
    public static int i = 0;
    public int j = 1;
    public static String getStaticString() {
        int k = 2;
        return s;
    }
    public String getString() {
        int l = 3;
        return "something";
    }
}

在Java中,静态变量存储在“堆段”的“Perm”代中,原始局部变量存储在“栈段”中。那么变量i,j,k,l存储在哪里?函数getString()存储在哪里?

"原始变量存储在堆栈段中"... 你确定你读对了吗?或者可能有一个漏字,比如“原始_局部_变量”?我认为你所说的静态变量适用于任何类型的静态变量。 - ajb
"局部变量"存储在堆栈段中。所有其他变量都存储在堆中的某个位置。 静态变量(至少在概念上)与类的Class对象一起存储,而实例变量与每个实例一起存储。 方法字节码(静态和实例)存储在C堆存储器中 - 不是Java堆的一部分。 - Hot Licks
1个回答

3

这些是实现细节,我们无法确定每个实现的具体情况,除非首先阅读和理解其源代码。就我的知识和经验而言,对于桌面JVM来说,最合理的假设如下:

  • si是静态变量。静态变量可能分配在堆上,位于永久代。
  • j存储在A类的实例中。类实例可以存在于栈上(如果引用的逃逸分析证明该引用具有自动存储语义并且它们足够小)或堆上(如果未执行逃逸分析或逃逸分析不确定或该实例过大以至于无法放入栈中)。
  • k是一个具有自动存储语义的局部变量,因此应该存在于栈上。当进入包含它的方法(getStaticString)时分配它,当退出包含它的方法时释放它。
  • lk的语义相同。其所在的方法(getString)不是静态的,这一点是无关紧要的。
  • getString(以及任何其他用户代码,无论其语言属性如何,如静态、非静态等)有两个表示形式:
    • 其元数据和字节码(AOT编译)是其所在类的类数据的一部分。它在内存中的生命周期可能与加载/卸载与此代码相关联的类有关,但不与该类的任何特定实例相关。换句话说,非静态方法并不是每次创建实例时都会"创建"。
    • 其编译后的代码(JIT编译)应永久驻留在单独的内存段中(JIT编译器的非托管堆的一部分,写入并标记为可执行),与Java对象的生命周期无关。

2
getString在一般情况下具有字节码表示和JITC表示。第一个存储在此类的Class对象中(尽管实际上可能存储在C堆中,而不是“permgen”),而第二个存储在JITC的可执行堆段中(这是一种C堆)。 - Hot Licks
@HotLicks 没错!我没有想到 OP 可能在询问非可执行表示。我会进行编辑。 - Theodoros Chatzigiannakis
对于“j”,我们能否说只有在创建一个新的“A”实例时,如“A a = new A();”,然后才会分配j?而“a”将存储在堆段中,所以“j”也存储在堆段中? - coderz
@coderz 当分配a时,它的一部分空间被保留给j。如果a在堆上,则j也在堆上。 - Theodoros Chatzigiannakis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接