什么时候最好使用堆栈而不是堆,反之亦然?
在C ++中,什么时候最好使用堆栈?什么时候最好使用堆?
解决方案
使用堆仅在运行时为对象分配空间。如果我们知道编译时的大小,请使用堆栈。与其从函数返回堆分配的对象,不如将缓冲区传递给函数以供其写入。这样,可以在将函数称为数组或者其他基于堆栈的结构的地方分配缓冲区。
我们拥有的malloc()语句越少,内存泄漏的机会就越少。
当前函数返回后将不使用变量时,请使用堆栈。在当前函数的生存期之外需要变量中的数据时,请使用堆。
这个问题与(虽然不是真正的骗子)与几天前问到的堆栈和堆在哪里以及什么有关。
这个问题病态严重。
在某些情况下,我们需要堆栈,其他情况下需要堆,其他情况下需要静态存储,其他情况下需要const内存数据,其他情况下需要免费存储。
堆栈速度很快,因为分配只是SP上的一个"增量",而所有"分配"都是在我们所使用的函数调用时执行的。堆(或者免费存储)分配/取消分配的时间更昂贵,并且容易出错。
根据经验,避免在堆栈上创建巨大的对象。
- 在堆栈上创建对象可以使我们免于记住清理(读取删除)对象的负担。但是在堆栈上创建太多对象会增加堆栈溢出的机会。
- 如果将堆用作对象,则将获得OS可以提供的尽可能多的内存,该内存要比堆栈大得多,但是,在完成后,必须再次确保释放内存。同样,在堆中创建太多的对象会导致内存碎片化,进而影响应用程序的性能。
当所使用的内存严格限于创建内存的范围时,请使用堆栈。这对于避免内存泄漏很有用,因为我们可以确切地知道要在哪里使用内存,并且知道何时不再需要它,以便为我们清除内存。
int main() { if (...) { int i = 0; } // I know that i is no longer needed here, so declaring i in the above block // limits the scope appropriately }
但是,当可能在其创建范围之外访问内存并且我们不希望复制堆栈变量时,该堆很有用。这可以使我们明确控制如何分配和释放内存。
Object* CreateObject(); int main() { Object* obj = CreateObject(); // I can continue to manipulate object and I decide when I'm done with it // .. // I'm done delete obj; // .. keep going if you wish return 0; } Object* CreateObject() { Object* returnValue = new Object(); // ... do a bunch of stuff to returnValue return returnValue; // Note the object created via new here doesn't go away, its passed back using // a pointer }
显然,这里的一个常见问题是我们可能忘记删除对象。这称为内存泄漏。随着程序变得越来越琐碎,"所有权"(或者确切负责删除内容的人)变得更加难以定义,这些问题变得越来越普遍。
使用更多托管语言(C#,Java)的常见解决方案是实现垃圾回收,因此我们不必考虑删除内容。但是,这意味着在后台有一些东西会不定期地运行以检查堆数据。在非平凡的程序中,这会变得非常低效,因为"垃圾回收"线程弹出并弹出,寻找应删除的数据,而程序的其余部分则无法执行。
在C ++中,处理内存泄漏的最常见也是最好的解决方案是使用智能指针。其中最常见的是boost :: shared_ptr,它是(引用计数)
所以要重新创建上面的例子
boost :: shared_ptr CreateObject();
int main() { boost::shared_ptr<Object> obj = CreateObject(); // I can continue to manipulate object and I decide when I'm done with it // .. // I'm done, manually delete obj.reset(NULL); // .. keep going if you wish // here, if you forget to delete obj, the shared_ptr's destructor will note // that if no other shared_ptr's point to this memory // it will automatically get deleted. return 0; } boost::shared_ptr<Object> CreateObject() { boost::shared_ptr<Object> returnValue(new Object()); // ... do a bunch of stuff to returnValue return returnValue; // Note the object created via new here doesn't go away, its passed back to // the receiving shared_ptr, shared_ptr knows that another reference exists // to this memory, so it shouldn't delete the memory }
作为经验法则,请尽可能使用堆栈。即当该范围之外永远不需要该变量时。
它的速度更快,导致碎片减少,并且将避免与调用malloc或者new相关的其他开销。从堆栈中分配是几个汇编程序操作,malloc或者new是有效实现中的数百行代码。
永远不要使用堆...这是不可避免的。 :)
上面提到的规则的一个例外情况是,通常应将堆栈用于函数范围之外不需要的局部变量:
如果递归函数分配了较大的局部变量或者被递归调用多次,则会耗尽堆栈空间。如果我们有一个利用内存的递归函数,则最好使用基于堆的内存而不是基于堆栈的内存。