Java 当堆栈弹出时,内存会发生什么变化?

Java 当堆栈弹出时,内存会发生什么变化?,java,c,jvm,Java,C,Jvm,我有一个函数 public void f() { int x = 72; return; } 因此,x可能存储在地址0x9FFF处 当函数返回时,该地址的内存发生了什么变化?它还在吗?即该值是否仍然72?或者它完全无效了?我不是马上看规范,但我猜这不是技术定义 我曾经在C++中尝试过类似的东西,实际上,它是 72代码>代码(或者我在函数调用之前放的任何东西)如果我没有记错,所以机器实际上没有经过,并把代码> 0 < /> >写入那个位置或某物。 其中一些也是实现细节。我也用MI

我有一个函数

public void f() {
    int x = 72;
    return;
}
因此,
x
可能存储在地址
0x9FFF


当函数返回时,该地址的内存发生了什么变化?它还在吗?即该值是否仍然
72
?或者它完全无效了?

我不是马上看规范,但我猜这不是技术定义

我曾经在C++中尝试过类似的东西,实际上,它是<代码> 72代码>代码(或者我在函数调用之前放的任何东西)如果我没有记错,所以机器实际上没有经过,并把代码> 0 < /> >写入那个位置或某物。

其中一些也是实现细节。我也用MIPS汇编语言实现了它(如果我能找到它,我将包括一个代码示例)。基本上,当我需要寄存器时,我只需按我需要的本地变量的多少来“增长”堆栈,存储我需要的寄存器中的当前值(以便以后恢复它们),然后重新使用寄存器。如果这是实现,那么该值实际上可以包含调用者中局部变量的值。不过,我不认为Java正是这么做的


TL;DR这是一个实现细节,但在C语言中,至少在实际需要之前,它不会覆盖内存中的值。Java要难预测得多。

我不是马上看规范,但我猜这不是技术定义

我曾经在C++中尝试过类似的东西,实际上,它是<代码> 72代码>代码(或者我在函数调用之前放的任何东西)如果我没有记错,所以机器实际上没有经过,并把代码> 0 < /> >写入那个位置或某物。

其中一些也是实现细节。我也用MIPS汇编语言实现了它(如果我能找到它,我将包括一个代码示例)。基本上,当我需要寄存器时,我只需按我需要的本地变量的多少来“增长”堆栈,存储我需要的寄存器中的当前值(以便以后恢复它们),然后重新使用寄存器。如果这是实现,那么该值实际上可以包含调用者中局部变量的值。不过,我不认为Java正是这么做的


TL;DR这是一个实现细节,但在C语言中,至少在实际需要之前,它不会覆盖内存中的值。Java更难预测。

Java编程语言和Java虚拟机都没有定义堆栈帧弹出后内存会发生什么变化。这是一个低级实现细节,被高级抽象所掩盖。事实上,Java语言和JVM字节码在设计上使得从堆栈中检索已经删除的值变得不可能(与C/C++不同)

然而,在实践中,Java中的堆栈帧的行为与C中的堆栈帧类似。增加堆栈会使其指针(通常向下)跳动,并分配空间来存储变量。收缩堆栈通常会使指针向上移动,只会让内存中的旧值腐烂,而不会覆盖它们。如果您对JVM的堆栈内存区域具有低级访问权限,那么这就是您应该看到的行为

请注意,在Java中不可能像C那样尝试读取未初始化的堆栈变量:

static boolean firstTime = true;

public void f() {
    int x;
    if (firstTime) {
        x = 72;
        firstTime = false;
    } else {
        // Compile error: Variable 'x' may not have been initialized
        System.out.println(x);
    }
}

JVM实现中可能存在其他堆栈行为。例如,当弹出帧时,可以将4 KiB虚拟内存页取消映射回操作系统,这将实际擦除旧值。此外,在计算机体系结构(如)上,堆栈内存经过特殊处理,因此增加堆栈始终会返回一个填充了零字节的区域,这节省了从内存实际加载旧值的工作。

Java编程语言和Java虚拟机都没有定义在弹出堆栈帧后堆栈帧的内存会发生什么情况。这是一个低级实现细节,被高级抽象所掩盖。事实上,Java语言和JVM字节码在设计上使得从堆栈中检索已经删除的值变得不可能(与C/C++不同)

然而,在实践中,Java中的堆栈帧的行为与C中的堆栈帧类似。增加堆栈会使其指针(通常向下)跳动,并分配空间来存储变量。收缩堆栈通常会使指针向上移动,只会让内存中的旧值腐烂,而不会覆盖它们。如果您对JVM的堆栈内存区域具有低级访问权限,那么这就是您应该看到的行为

请注意,在Java中不可能像C那样尝试读取未初始化的堆栈变量:

static boolean firstTime = true;

public void f() {
    int x;
    if (firstTime) {
        x = 72;
        firstTime = false;
    } else {
        // Compile error: Variable 'x' may not have been initialized
        System.out.println(x);
    }
}
JVM实现中可能存在其他堆栈行为。例如,当弹出帧时,可以将4 KiB虚拟内存页取消映射回操作系统,这将实际擦除旧值。此外,在计算机体系结构(如堆栈)上,对内存进行了特殊处理,因此增加堆栈总是会返回一个填充了零字节的区域,这节省了实际从内存加载旧值的工作。

在C中,这是未定义的行为

在实践中,如果您尝试以下方法:

 int *ptr;

 void foo() {
    bar();
    printf("%d", *ptr);
 }

 void bar() {
     int x = 72;
     ptr = &x;
 }
然后,在大多数C实现中,
foo()
可能会打印
72
。这是因为尽管ptr引用的地址可以重新分配,但它不太可能被重新分配,并且没有任何内容覆盖该内存。程序继续运行的时间越长,初始化更多的局部变量,并调用
malloc()
,该内存地址被重复使用的可能性就越大,值也会改变

然而,在C规范中并没有任何内容说明这种情况——一种实现