4

这些主要是编译器设计问题。当您的编译器编译它时,例如:

int * pData = new int[256];

内存是如何动态分配的?编译器是调用为您分配内存的 OS 例程还是为您分配内存的已编译函数?

另外,当你写这样的东西时:

if (x == 5)
    int y;

由于内存不是在运行时分配的,我假设数据在程序的数据段中占用了一些空间。由于编译器无法真正确定int y;分支是否会在运行时执行,那么是否为变量保留了内存int y;呢?如果无论如何都保留它,内存分配可能会或可能不会执行的块中的任何变量不是更节省内存吗?

哦谢谢

4

7 回答 7

6

对于第一个问题:new编译器遇到运算符时,例如您的示例:

int * pData = new int[256];

它有效地发出如下代码:

int *pData = reinterpret_cast<int*>(::operator new(256 * sizeof(int)));
// the compiler may also choose to reserve extra space here or elsewhere to
// "remember" how many elements were allocated by this new[] so delete[] 
// can properly call all the destructors too!

如果应该调用构造函数,那么也会发出(在这个例子中,我相信没有调用构造函数)。

operator new(std::size_t)是一个由标准库实现的函数,通常但并非总是如此,它会归结为一个malloc调用。

malloc将不得不进行系统调用,以从操作系统请求内存。由于操作系统分配器通常使用较大的固定大小的内存块,malloc因此不会每次都进行此调用,只有在它耗尽当前拥有的内存时才进行此调用。


对于第二个问题:对于局部变量,它确实取决于编译器。该标准没有提到堆栈。但是,您很可能处于运行通用操作系统并使用通用编译器的通用架构上:-)。

因此,对于常见情况,编译器通常会在函数调用开始时为所有局部变量保留空间,方法是相应地调整堆栈或为它们保留寄存器(如果可以)(寄存器是首选,因为它更快)。

然后(在c++中),当遇到变量时,它会调用构造函数。理论上,它可以根据需要调整堆栈,但这会很复杂,无法证明正确且效率较低。通常保留堆栈空间是一条指令,因此一次完成所有操作是非常理想的。

于 2011-04-04T20:56:02.013 回答
2

内存是如何动态分配的?编译器是调用为您分配内存的 OS 例程还是为您分配内存的已编译函数?

在大多数实现中,它是这两者的组合。通常有一个操作系统服务用于为您的进程提供内存块,以及运行时或标准库中的一些代码,用于在应用程序内以更细粒度的规模管理这些内存块。

是为变量保留的内存,无论是否“int y;” 被执行?如果无论如何都保留它,内存分配可能会或可能不会执行的块中的任何变量不是更节省内存吗?

通常,否 -y仅当执行适当的代码时才会分配空间。具有自动存储类的变量通常在堆栈上,因此为它们腾出空间就像修改堆栈指针一样简单。也就是说,在这种情况下,编译器几乎可以做它想做的任何事情,因此检查工具链的输出是确定的唯一方法。

于 2011-04-04T20:51:04.160 回答
1

局部变量 (int y) 在堆栈上分配。

指针也是如此,但是“new”表达式是在堆上分配的,通​​常是通过各种 malloc 调用。确切的方法和堆布局是实现定义的。

数据段中只有全局静态数据。

示例 int y 将被优化,因为它没有被使用。

与例如 C# 不同,C++不允许缩小变量的范围,因此在 { SomeClass y; } 可以提供帮助,所以它会更早地被破坏

但是,我很确定对于简单类型(如 int)不存在这样的限制,因为它们永远不会有析构函数

于 2011-04-04T20:51:03.557 回答
1

关于你的第二个问题,条件代码中的变量是一个自动变量。通常这些是在堆栈上分配的。在这种情况下,一个好的编译器会注意到它永远不会被读取或写入,甚至不会为它在堆栈上分配空间。

于 2011-04-04T20:51:59.737 回答
0

这实际上取决于第二个示例的编译器,这就是为什么我们有 volatile 关键字(以防我们将变量映射到更改的地址)或者它可能只是给你一个警告,但我相当肯定它会将它包含到你的程序中(有时出于骇人听闻的原因,您想增加方法的堆栈大小)。第一个示例实质上调用 malloc(256 * sizeof(int)) 并返回指向该段的指针。

于 2011-04-04T20:51:24.457 回答
0

情况 1:它将调用 OS 例程在堆上分配内存。操作系统管理内存。

情况2:这是在堆栈上分配的。堆栈预先分配给您的进程,并用于局部变量和函数参数。

于 2011-04-04T20:51:35.743 回答
0

对于第一个问题:

编译器生成代码来调用函数operator new,它本身通常malloc从 C 运行时库调用,它本身会调用一些特定于操作系统的库,这些库(你可以看到这是怎么回事)在某些时候最终会切换到内核模式和为进程分配内存。

无论如何,编译器为您自己的程序生成的本机代码不会自行分配。

对于第二个问题:

的内存int y是在堆栈上分配的。无论条件是否为真,在最简单的非优化情况下,每次控制进入您的函数时都会发生堆栈空间分配。

由于堆栈分配只是几个寄存器操作,无论要分配多少空间,都需要相同的时间,而且一旦函数返回,内存就会被回收,所以这里不存在“内存占用”问题。

于 2011-04-04T20:53:01.480 回答