C ++可变内存分配

时间:2011-04-04 20:46:25

标签: c++ memory-management compiler-theory conditional-compilation new-operator

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

int * pData = new int[256];

如何即时分配内存?编译器是否调用为您分配内存的OS例程,或者是为您分配内存的函数?

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

if (x == 5)
    int y;

由于内存未在运行时分配,我假设数据占用了程序数据段的一些空间。由于编译器无法确定int y;分支是否将在运行时执行,因此是否为int y;执行了为变量保留的内存?如果它是保留的,那么mem分配块中可能会或可能不会执行的任何变量的内存效率是否更高?

o.o谢谢

7 个答案:

答案 0 :(得分: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必须生成system call,才能从操作系统请求内存。由于操作系统分配器通常使用较大的固定大小的内存块,malloc每次都不会进行此调用,只有当它已经耗尽了当前的内存时才会使用。


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

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

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

答案 1 :(得分:2)

  

如何即时分配内存?编译器是否调用为您分配内存的OS例程,或者是为您分配内存的函数?

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

  

是为变量保留的内存,无论是否为“int y;”执行?如果它是保留的,那么mem分配块中可能会或可能不会执行的任何变量的内存效率是否更高?

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

答案 2 :(得分:1)

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

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

只有全局静态数据存在于数据段中。

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

与...不同C#,C ++ not 允许减少变量的范围,因此在{SomeClass y中包装一个短的本地;可能有帮助,所以它会被破坏

但是,我很确定对于简单类型(如int)没有这样的限制,因为那些

永远不会有析构函数

答案 3 :(得分:1)

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

对于第一个问题:

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

在任何情况下,编译器为您自己的程序生成的本机代码都不会自行进行分配。

关于第二个问题:

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

由于堆栈分配只是几个寄存器操作,无论分配多少空间都需要相同的时间,并且因为一旦函数返回就会回收内存,这里没有“内存耗尽”问题