繁体   English   中英

堆栈框架问题:Java 与 C++

[英]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 )是通过引用传递的。 变量localObjdoHello指回堆栈变量。 如果您更改它,则更改将存储在分配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" 成员分配给哪个对象。

此处列出C++ 中的所有内存区域

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM