什么时候最好使用栈而不是堆,反之亦然?
在C ++中,何时最好使用堆栈? 什么时候最好使用堆?
在当前函数返回后,当variables不被使用时使用堆栈。 当variables中的数据超出当前函数的使用期限时,使用堆。
根据经验,避免在堆栈上创build巨大的对象。
- 在堆栈上创build一个对象可以让你免除清理(读取删除)对象的负担。 但是在堆栈上创build太多对象会增加堆栈溢出的可能性。
- 如果你使用堆对象,你会得到尽可能多的操作系统可以提供的内存,比堆栈大得多,但是当你完成后,你必须确保释放内存。 另外,在堆中过多地创build太多对象往往会使内存碎片化,进而影响应用程序的性能。
当正在使用的内存严格限制在您创build它的范围时使用堆栈。 这对于避免内存泄漏非常有用,因为您确切知道您要使用内存的位置,并且知道何时不再需要内存,因此内存将被清除。
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 }
但是,如果您的内存可能在创build范围之外访问,并且您不希望复制堆栈variables,那么堆是非常有用的。 这可以给你明确的控制内存如何分配和释放。
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 }
显然这里的一个共同的问题是,你可能会忘记删除你的对象。 这被称为内存泄漏。 这些问题比较普遍,因为你的程序变得越来越不重要,因为“所有权”(或者究竟是谁负责删除东西)变得更难以定义。
更多pipe理语言(C#,Java)的通用解决scheme是实现垃圾收集,所以你不必考虑删除东西。 但是,这意味着在后台有一些东西会不定期地检查你的堆数据。 在一个非平凡的程序中,当“垃圾回收”线程popup并突然消失,查找应该删除的数据,而其他程序被阻止执行时,这可能变得相当低效。
在C ++中,处理内存泄漏的最常见和最好的(在我看来)解决scheme是使用智能指针。 其中最常见的是boost :: shared_ptr ,它是( 引用计数 )
所以重新创build上面的例子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 }
上面提到的规则的一个例外是,您通常应该使用堆栈来存储函数范围之外不需要的局部variables:
如果recursion函数分配大的局部variables或recursion调用多次,recursion函数会耗尽堆栈空间。 如果你有一个利用内存的recursion函数,那么使用基于堆的内存而不是基于堆栈的内存可能是个好主意。
这个问题是相关的(虽然不是真正的愚弄) 什么,堆栈和堆在哪里 ,这是几天前问。
使用堆只在运行时为对象分配空间。 如果你知道编译时的大小,使用堆栈。 不要从函数返回堆分配的对象,而是将缓冲区传递给函数来写入。 这样,缓冲区可以被分配到函数被调用为数组或其他基于堆栈的结构中。
您拥有的malloc()语句越less,内存泄漏的机会就越less。
根据经验,尽可能使用堆栈。 即在该范围之外从不需要variables的时候。
它更快,导致更less的碎片,并将避免与调用malloc或新的相关的其他开销。 分配堆栈是几个汇编操作,malloc或new是有效实现中的几百行代码。
它从来没有最好的使用堆…只是不可避免的。 🙂
这个问题是不健康的。
有些情况下需要堆栈,其他需要堆的地方,其他需要静态存储的地方,其他需要常量内存数据的地方以及需要免费存储的地方。
堆栈速度很快,因为分配只是SP上的一个“增量”,所有的“分配”都是在你所在函数的调用时执行的。堆(或自由存储)分配/释放更为耗时且容易出错。
- UnobservedTaskException被抛出,但它由TaskScheduler.UnobservedTaskException处理程序和一个continuation OnlyOnFaulted处理程序处理
- 有没有一个通用的Parse()函数,将string转换为任何types使用parsing?
- 是否有可能强制一个函数不内联?
- Java相当于#地区在C#
- 新的数据写入时,富文本框滚动到底部
- 在C#中声明一个const double ?
- System.Timers.Timer / Threading.Timer与线程与WhileLoop + Thread.Sleep的周期性任务
- 你如何构build一个embedded式null的std :: string?
- 用哪种语言编写的C#编译器?