gpt4 book ai didi

java - 如何在Java中访问堆栈内存

转载 作者:行者123 更新时间:2023-12-02 01:23:10 26 4
gpt4 key购买 nike

我试图了解Java堆栈和堆内存。通过不同来源的阅读,我得出以下结论:


在本地(方法的一部分)声明的基本类型,例如int,
字节,字符等存储在堆栈中。
静态和实例(对象实例或类的一部分)原始类型存储在堆中。
简而言之,局部变量存储在堆栈中,而实例变量和静态变量存储在堆中。
本地引用的对象将在堆中创建,但是变量将在堆栈中创建。
实例/静态引用的对象将在堆中同时创建变量和对象。


(例如,本地car ferrari = new car()将在堆栈中为ferrari创建内存,而实际对象将在堆中。

堆栈变量ferrari将具有实际对象堆位置的引用地址。

但是在进一步阅读时,我读到了堆栈中的内存分配给了前一帧的顶部。这让我对以下情况感到困惑:

问题1:

让我的方法是:

calculate(){
int a=15;
int b=25;

return a+b;
}


但根据堆栈,后进将为b。因此,a的价值将消失
 直到从堆栈中使用b的值为止。

程序如何使用'b'之前的'a'值?为了
操作a + b。

问题2:

让我的方法是:

calculate(){
int a=15;
int b=25;
int z= a+b;
int y=a+b;

return y;

}


现在我已经使用变量a和b来计算“ z”,如何
变量y可以再次访问a和b,因为它已经从
堆栈。

我不是Java方面的专家,如果有人可以用简单的语言进行解释,我非常感谢。

最佳答案

每个线程都有自己的堆栈。

每当线程调用方法时,都会在堆栈存储器中为该方法创建一个新块,以保存本地原始值并引用该方法中的其他对象。该存储块称为堆栈帧。方法结束后,该块将立即变为未使用状态,并将其从堆栈顶部移除。这是因为堆栈存储器始终按LIFO(后进先出)的顺序进行引用。

因此,如果您有代码:

void go(){
int x = 1;
foo(x);
}

void foo(int y){
int z = y;
bar();
}

void bar(){
Hello h = new Hello();
}


堆栈看起来像这样:

enter image description here

在此图片上,仅 h处于范围内。但是在完成 bar()方法之后, yz这两个变量都将在范围内。

在内部,堆栈包含局部变量数组和操作数堆栈。

在局部变量数组中存储了方法的参数以及该堆栈框架的所有局部变量。同样,如果堆栈框架表示实例方法,则在局部变量数组的位置 0上将是 this引用,该引用指向堆上的对象。如果method是 static,则位置 0上的将是该方法的第一个参数。局部变量数组的大小在编译时确定。要查看局部变量数组,您需要查看已编译的Java代码。对于第一个 calculate()方法(如果是 static),局部变量数组将如下所示:

enter image description here

您可以看到变量名称( Name列)与其在数组中的位置( Slot列)之间的关系。

操作数堆栈是用于对局部变量数组中的变量进行操作的堆栈。在操作数栈中是放置并从局部变量数组中获取的变量,在您的示例中,将其添加并分配给其他变量,这些变量再次保存在局部变量数组中。

问题1:
程序如何将 a之前的 b值用于操作 a + b

因为存在弹出操作,该操作读取然后从堆栈中删除值。要添加这两个值,请从操作数堆栈中弹出(读取和删除)最后一个值(值 b)。现在,值 a在操作数堆栈的顶部。同时弹出(读取和删除)此值(操作数堆栈现在为空),并将这两个值相加。将结果放回操作数堆栈。现在,操作数堆栈仅包含结果。

详细说明:
当您调用 calculate()时,将创建新的堆栈框架并将其放在堆栈顶部。语句 int a = 15;在内部分为2个步骤:


常量 15放在操作数堆栈的顶部,
从操作数堆栈中弹出(读取和删除)值(这是常量 15),并将其保存在特定索引的局部变量数组中。


int b = 25;重复相同的步骤。现在,您有2个值保存在局部变量数组和空操作数堆栈中。最后的 return a + b;分4个步骤完成:


将值 a从局部变量数组推送(加载)到操作数堆栈,
将值 b从局部变量数组推入(加载)到操作数堆栈。现在,操作数堆栈上有两个值。
从操作数堆栈中弹出(读取和删除)第一个值(这是 b值)。从操作数堆栈中弹出第二个值(这是 a值)。此时,操作数堆栈为空。将这两个值相加并将结果推回操作数堆栈。现在操作数堆栈仅包含加法运算的结果。
从操作数堆栈中弹出值,并将其返回给调用此方法的任何人。现在操作数堆栈为空。


此时,因为方法已完成,所以从堆栈中删除了堆栈框架。

问题2:
现在,我已经使用变量 ab来计算 z,变量 y如何能够再次访问 ab,因为已经从堆栈中使用了它?

因为在堆栈框架内有一个局部变量数组,用于存储在该堆栈框架中定义的所有局部变量。

详细说明:
  int a = 15int b = 25以与Q1中相同的方式进行。 int z = a + b;是这样执行的:


将值 a从局部变量数组推送(加载)到操作数堆栈,
将值 b从局部变量数组推入(加载)到操作数堆栈。现在,操作数堆栈上有两个值。
从操作数堆栈中弹出(读取和删除)第一个值(这是 b值)。从操作数堆栈中弹出第二个值(这是 a值)。此时,操作数堆栈为空。将这两个值相加并将结果放在操作数堆栈上。现在操作数堆栈仅包含加法运算的结果。
从操作数堆栈中弹出(读取和删除)值( a + b结果),并将其保存在特定索引的局部变量数组中。


int y = a + b;的执行方式与 int z = a + b;相同。

最后一部分 return y


y值从局部变量数组推入操作数堆栈,
从操作数堆栈中弹出值,并将其返回给调用此方法的任何人。操作数堆栈现在为空。


因为方法已完成,所以从堆栈中删除了堆栈框架。

请注意,存在多个堆栈框架中包含的堆栈,而且每个堆栈框架中都有用于该堆栈框架内部操作的操作数堆栈。

关于java - 如何在Java中访问堆栈内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57336595/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com