use*_*498 45 c++ memory memory-leaks memory-management delete-operator
让我们说我有这样的功能:
int main()
{
char* str = new char[10];
for(int i=0;i<5;i++)
{
//Do stuff with str
}
delete[] str;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
str
如果我要结束程序,为什么还需要删除?如果我要退出,我不在乎那个记忆是否会到达满是独角兽的土地,对吧?
这只是好习惯吗?
它有更深的后果吗?
Eri*_*ert 77
如果事实上你的问题确实是"我有这个琐碎的程序,那么在它退出之前我不会释放几个字节吗?" 答案是肯定的,那没关系.在任何现代操作系统上都会很好.该计划是微不足道的; 这并不是说你要把它放入心脏起搏器或用这个东西运行丰田凯美瑞的制动系统.如果唯一的客户是你,那么你唯一可能因为草率而可能影响的人就是你.
当你从这个问题的答案开始概括到非平凡的案例时,问题就出现了.
因此,让我们提出两个关于一些非平凡案例的问题.
我有一个长期运行的服务,以复杂的方式分配和释放内存,可能涉及多个分配器打多个堆.在正常模式下关闭我的服务是一个复杂且耗时的过程,涉及确保外部状态 - 文件,数据库等 - 始终关闭.在关闭之前,我应该确保分配的每个内存字节都被释放吗?
是的,我会告诉你原因.长期运行服务可能发生的最糟糕的事情之一就是它会意外泄漏内存.即使很小的泄漏也会随着时间的推移而增加大量泄漏.查找和修复内存泄漏的标准技术是检测分配堆,以便在关闭时记录所有已分配但未释放的资源.除非你喜欢追了很多误报并在调试花费了大量的时间,总是释放你的记忆,即使这样做是不是严格意义上讲必要.
用户已经预计关闭服务可能需要数十亿纳秒,所以谁在乎你是否会对虚拟分配器造成一点额外的压力,确保一切都被清理干净?这只是您为大型复杂软件支付的价格.并不是说你一直在关闭服务,所以再次,谁在乎它是否比它可能慢几毫秒?
我有同样长期运行的服务.如果我发现我的一个内部数据结构已损坏,我希望"快速失败".该程序处于未定义状态,它可能以提升的权限运行,我将假设如果我检测到已损坏的状态,那是因为我的服务正在被敌对方主动攻击.最安全的做法是立即关闭服务.我宁愿允许攻击者拒绝为客户提供服务,也不愿让服务熬夜并进一步损害我的用户数据.在这个紧急关闭场景中,我应该确保我分配的每个内存字节都被释放了吗?
当然不是.操作系统将为您处理.如果您的堆已损坏,攻击者可能希望您将内存作为其漏洞利用的一部分.每毫秒都很重要.为什么在你在建筑物上放置战术核武器之前,你还要打扰门把手和拖地厨房吗?
所以问题的答案"我应该在程序退出之前释放内存吗?" 是"这取决于你的程序做什么".
75i*_*ist 39
是的,这是好习惯.你永远不应该假设你的操作系统会照顾你的内存释放,如果你养成这种习惯,它会在以后搞砸你.
但是,要回答您的问题,在退出main时,操作系统会释放该进程占用的所有内存,因此包括您可能生成的任何线程或分配的变量.操作系统将负责释放内存以供其他人使用.
Rod*_*ddy 24
重要提示:delete
释放内存几乎只是一种副作用.它的重要作用是破坏对象.使用RAII设计,这可能意味着关闭文件,释放操作系统句柄,终止线程或删除临时文件.
当您的进程退出时,操作系统会自动处理其中一些操作,但不是全部.
在你的例子中,没有理由不打电话delete
.但也没有理由打电话new
,所以你可以这样回避问题.
char str[10];
Run Code Online (Sandbox Code Playgroud)
或者,您可以通过使用智能指针来回避删除(以及涉及的异常安全问题)...
因此,通常您应该始终确保对象的生命周期得到妥善管理.
但这并不总是那么容易:静态初始化顺序惨败的变通方法通常意味着你别无选择,只能依靠操作系统为你清理一些单例类型的对象.
Ben*_*son 16
相反的答案:不,这是浪费时间.具有大量分配数据的程序几乎必须触及每个页面才能将所有分配返回到空闲列表.这会浪费CPU时间,为不感兴趣的数据创建内存压力,甚至可能导致进程从磁盘交换页面.只需退出即可将所有内存释放回操作系统,无需任何进一步操作.
(不是我不同意"是"中的原因,我只是认为两种方式都存在争议)
退出程序时,您的操作系统应该处理内存并进行清理,但通常的做法是释放您保留的内存.我个人认为最好是进入这样做的正确心态,因为当你做简单的程序时,你很可能这样做是为了学习.
无论哪种方式,保证释放内存的唯一方法就是自己动手.
归档时间: |
|
查看次数: |
2681 次 |
最近记录: |