在我的应用程序中,我基本上在C++
中分配内存,并将其排队以便在C#
中重新分配。这种解除分配在后台运行并且是非确定性的,所以在非常罕见的情况下理论上可以发生应用程序在所有非托管内存被释放之前退出。
如果是这种情况,行为(粗略和非常简单)就像我的程序
一样int main()
{
Foo* = new Foo();
return 0;
}
我现在的问题是
修改 这仅限于Windows,因为有些人提到这是依赖于操作系统的。
编辑2: 我不是在谈论简单地忽略我的应用程序中的所有内存泄漏,而是关于我是否需要确保在应用程序退出之前正确释放所有内存。
编辑3: 这不是关于打开文件句柄,析构函数和副作用或任何东西,这是关于将被非确定性地解除分配的内存以及在终止之前不释放内存的非常罕见的情况。
答案 0 :(得分:4)
程序是否分配了所有内存,但是当程序退出时是否会自动回收解除分配,还是在重新启动之前一直存在内存泄漏?
当进程终止时,操作系统会自动回收内存。
如果它被自动回收,那么由什么机制负责呢?
C ++的内存管理器,new
,delete
,malloc
后面的内存管理器从操作系统的相对较大的块中获取内存,并负责管理内存块更小的粒度。操作系统跟踪已分配给进程的所有内存,并在进程终止时回收它。
答案 1 :(得分:3)
除非您正在开发低级别,否则您需要在操作系统下工作。该操作系统管理真实存储器,为您的应用程序提供映射到真实存储器的虚拟存储器。
关闭应用程序后(它的进程终止),操作系统会删除虚拟内存映射,从而释放该进程的所有内存资源。
答案 2 :(得分:2)
如果您只关心内存,则可能不需要致电delete
,因为操作系统会在virtual address space终止时销毁整个process。考虑阅读Operating Systems: Three Easy Pieces(可免费下载)以了解有关操作系统的更多信息。
但是你想避免使用memory leak,所以你最好能够正常清理。在某些操作系统上,您可以使用valgrind之类的工具来帮助检测此类泄漏(因此您不希望它们发出虚假警告)。
另请阅读RAII。在现实生活中,Foo
的构造函数(或其他方法)(或它使用的间接数据)可能会消耗其他资源(数据库连接,打开的文件,屏幕上的窗口,守护程序进程,与外部服务的远程连接或网络服务器,机器人手臂等......)你希望它们得到妥善处理。
考虑使用smart pointers。
数据结构的活跃性是整个程序属性。我建议阅读GC handbook,至少要理解garbage collection的概念和术语(可以将其视为一种管理资源的方式,而不仅仅是原始内存)。
(实际上,它很大程度上取决于:如果您正在与数百名其他程序员编写一百万行代码程序,那么您需要比编码时更加小心一个微小的单源文件程序;如果你编写一个神经外科手术机器人,它与桌面应用程序等不同......所以YMMV)
答案 3 :(得分:2)
答案是Windows应该在您之后清理内存,如果不这样做,则应将其视为操作系统中的错误。对于Linux以及任何其他可以过早杀死进程的系统也是如此。
原因,如果我理解正确,你所描述的情况也更类似于以下内容:
{{1}}
因此,即使您按照自己的意愿完成了所有操作,并且正确地进行了清理,但由于操作系统选项会过早地终止您的进程,因此会导致内存泄漏。
最后,一个重要的澄清,这并不意味着你可以一起忽略这个话题,你应该尽力清理自己,并且不要依赖其他系统来清理你。
答案 4 :(得分:2)
有两种不同级别的内存分配:
从操作系统到进程的内存分配。这需要syscall(brk()
或mmap()
),并且是完全实现定义的。 你自己从未见过。
从进程到单个数据对象的内存分配。这是operator new()
的作用。
new
返回指向数据对象的指针,因此主要关注第二级。但是,new
本身没有可以分配给对象的内存,除非它首先要求操作系统提供一些内存。因此,它需要首先执行第一级分配。
new
本身的实施完全在您的流程中。因此,当您的进程以不自然的方式死亡(由于信号而死亡)时,new
实现没有机会清理任何内容。但这不是必需的,因为操作系统本身会跟踪在第一级分配的内存。它根本不信任一些随机进程来跟踪它们自己分配的内存。因此,不会发生永久性内存泄漏。
但是,使用delete
创建的new
个对象失败会产生影响:
您的进程无法重用内存本身。如果您反复分配无法释放的对象,则new
实现将需要进行越来越多的第一级内存分配,直到您的操作系统没有剩余内存可用于您的进程。
否delete
表示未调用相应的析构函数。因此,您的过程可能会错过一些外部清理。例如,未能破坏对象可能意味着某些临时文件未从文件系统中删除,因此您的进程会泄漏磁盘空间而不是内存。而且你也不想要那个,是吗?