[英]Stack Frame Question: Java vs C++
一季度。 在Java中,所有的对象、数组和类变量都存储在堆上? C++ 也是如此吗? 数据段是堆的一部分吗?
下面的 C++ 代码怎么样?
class MyClass{
private:
static int counter;
static int number;
};
MyClass::number = 100;
Q2。 就我的理解,编译器赋予特定值的变量存储在数据段中,未初始化的全局和静态变量存储在 BSS(由符号开始的块)中。 在这种情况下,静态的 MyClass::counter 被编译器初始化为零,因此它存储在 BSS 中,而初始化为 100 的 MyClass::number 存储在数据段中。 我的结论正确吗?
Q3。 考虑以下代码:
void doHello(MyClass &localObj){
// 3.1 localObj is a reference parameter, where will this get stored in Heap or Stack?
// do something
}
void doHelloAgain(MyClass localObj){
// 3.2 localObj is a parameter, where will this get stored in Heap or Stack?
// do something
}
int main(){
MyClass *a = new MyClass(); // stored in heap
MyClass localObj;
// 3.3 Where is this stored in heap or stack?
doHello(localObj);
doHelloAgain(localObj);
}
我希望我已经向所有人说明了我的问题
编辑:
请参考这篇文章对 BSS 有一些了解
EDIT1:将类名从 MyInstance 更改为 MyClass,因为它是一个糟糕的名称。 诚挚的道歉
EDIT2:将类成员变量编号从非静态更改为静态
这有点简化,但据我所知,大部分都是准确的。
在 Java 中,所有对象都在堆上分配(包括所有成员变量)。 大多数其他东西(参数)是引用,引用本身与本机类型(整数、长整数等)一起存储在堆栈中,除了字符串,它更像是一个对象而不是本机类型。
在 C++ 中,如果要使用“new”关键字分配所有对象,它的情况与 java 几乎相同,但在 C++ 中有一种独特的情况,因为您可以改为在堆栈上分配对象(您并不总是必须使用“新”)。
还要注意,Java 的堆性能比 C 的堆性能更接近 C 的堆栈性能,垃圾收集器做了一些非常聪明的事情。 它仍然不如堆栈好,但比堆好得多。 这是必要的,因为 Java 无法在堆栈上分配对象。
第一季度
Java 还在堆栈上存储变量,但在堆上分配类实例。 在 C++ 中,您可以在堆栈或堆上自由分配类实例。 通过使用new
关键字,您可以在堆上分配实例。
数据段不是堆的一部分,而是在进程启动时分配的。 堆用于动态内存分配,而数据段是静态的并且内容在编译时是已知的。
BSS 段只是一种优化,其中所有属于数据段(例如字符串、常量等)的未初始化或初始化为零的数据都移动到 BSS 段。 数据段必须嵌入到可执行文件中,通过将“所有零”移动到末尾,它们可以从可执行文件中删除。 当加载可执行文件时,BSS 段被分配并初始化为零,编译器仍然能够知道 BSS 段内的各种缓冲区、变量等的地址。
Q2
MyClass::number
存储在分配MyClass
类的实例的位置。 它可以在堆上,也可以在堆栈上。 注意在 Q3 中a
如何指向在堆上分配的MyClass
的实例,而localObj
是在堆栈上分配的。 因此a->number
位于堆上,而localObj.number
位于堆栈上。
由于MyClass::number
是一个实例变量,您不能像这样分配它:
MyClass::number = 100;
但是,您可以分配MyClass::counter
因为它是静态的(除了它是私有的):
MyClass::counter = 100;
Q3
当您调用doHello
,变量localObj
(在main
)是通过引用传递的。 变量localObj
在doHello
指回堆栈变量。 如果您更改它,则更改将存储在分配main
中的localObj
的堆栈中。
当您调用doHelloAgain
,变量localObj
(在main
)被复制到堆栈中。 在doHelloAgain
内部,变量localObj
分配在堆栈上,并且仅在调用期间存在。
一季度。 在Java中,所有的对象、数组和类变量都存储在堆上? C++ 也是如此吗? 数据段是堆的一部分吗?
不,数据部分与堆分开。 基本上,数据部分是在加载时分配的,之后的所有内容都有一个固定的位置。 此外,可以在堆栈上分配对象。
对象位于堆上的唯一时间是使用new
关键字,或者使用malloc
系列函数中的某些内容。
Q2。 就我的理解,编译器赋予特定值的变量存储在数据段中,未初始化的全局和静态变量存储在 BSS(由符号开始的块)中。 在这种情况下,静态的 MyInstance::counter 被编译器初始化为零,因此它存储在 BSS 中,而初始化为 100 的 MyInstance::number 存储在数据段中。 我的结论正确吗?
是的,您对 BSS 部分的理解是正确的。 但是,由于number
不是静态的代码:
MyInstance::number = 100;
不合法,它需要在构造函数中正确设置为静态或初始化。 如果在构造函数中初始化它,它就会存在于分配拥有对象的任何地方。 如果您将其设为静态,它将最终出现在数据部分......如果在任何地方。 通常static const int
变量可以直接内联到所使用的代码中,这样根本不需要全局变量。
Q3。 考虑以下代码:...
void doHello(MyInstance &localObj){
localObj 是对传递对象的引用。 据您所知,没有存储,它指的是传递的变量在哪里。 实际上,在幕后,可能会在堆栈上传递一个指针以促进这一点。 但是如果可以的话,编译器也可以很容易地优化它。
void doHelloAgain(MyInstance localObj){
传递的参数的副本放置在堆栈中。
MyInstance localObj;
// 3.3 Where is this stored in heap or stack?
localObj 在堆栈上。
在 C++ 中,对象可能会在堆栈上分配……例如,Q3 主例程中的 localObj。
我感觉到一些关于类与实例的混淆。 “MyInstance”作为变量名比作为类名更有意义。 在您的 Q1 示例中,“数字”存在于 MyInstance 类型的每个对象中。 “计数器”由所有实例共享。 "MyInstance::counter = 100" 是一个有效的赋值,但 "MyInstance::number = 100" 不是,因为你还没有指定应该将它的 "number" 成员分配给哪个对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.