3

这些主要是编译器设计问题。当你的编译器编译这一点,例如:C++可变内存分配

int * pData = new int[256];

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

而且,当你写这样的事:

if (x == 5) 
    int y; 

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

o.o谢谢

回答

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,从OS请求内存。由于操作系统分配器通常使用更大的固定大小的内存块,因此只有当它耗尽了当前拥有的内存时,malloc才会每次都进行此调用。


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

所以对于共同情况下,编译器将典型地通过相应地调节叠层,或者如果它可以(寄存器是因为优选的选择保留的寄存器为它们保留在该函数调用的所有的局部变量的开头空间这是更快)。

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

1

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

指针也是一样,然而'new'ed表达式是在堆上分配的,通​​常是通过malloc调用。确切的方法和堆布局是实现定义的。

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

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

与例如C#,C++是而不是允许减少一个变量的范围,所以在{SomeClass y; }能帮上忙,所以它得到早期破坏

不过,我敢肯定,对于简单类型(如int)没有这样的限制存在,因为永远不会有那些

+0

对于简单类型int(或者几乎任何类型,作为一个简单的析构函数),该规则仍然适用,但优化通常仍然可以完成,因为“as if”规则。一个不能优化的例子就像'{int z = 42; foo(&z); bar(); baz();}',其中编译器无法看到foo bar和baz的实现(例如,因为它们是系统调用),那么编译器必须假定bar或baz可以访问z,因此在baz返回之前,不能重新使用分配给z的空间 – 2011-04-05 00:58:08

2

析构函数是怎么内存分配的内存?编译器是否调用了为您分配内存的OS例程,或者是编译过的为您分配内存的函数?

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

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

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

0

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

0

情况1:它会调用OS例程来分配堆上的内存。操作系统管理内存。情况2:这是在堆栈上分配的。该堆栈预分配给您的进程,并用于局部变量和函数参数。

+0

通常,操作系统将处理更大块的内存,并且C++库将有例程来处理这种规模的分配 – 2011-04-04 20:53:43

+0

在典型的实现中,是的, OS最终管理内存,但并不是每个'new'都会成为一个系统调用。 – 2011-04-04 20:54:48

1

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

0

对于第一个问题:

编译器生成的代码来调用该函数operator new,其本身通常从C运行时库,这本身就是对某些特定的OS-库,一个电话呼叫malloc(你可以看到这是怎么回事)在某个点最终切换到内核模式并为进程分配内存。

在任何情况下,该编译器生成你自己的程序不作分配本身的本地代码。

对于第二个问题:

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

由于堆栈分配只是少数几个需要同时分配的寄存器操作,无论分配多少空间,并且一旦函数返回就会回收内存,因此不存在“内存管理”问题这里。

+0

这个解释非常有用,谢谢。局部变量被搁置在一个堆栈框架中, – 2011-04-04 21:29:52