每个进程都可以使用堆内存来存储和共享进程内的数据。每当我们在堆内存中占用一些空间时,我们就有编程规则,我们需要在作业完成后释放它,否则会导致内存泄漏。
int *pIntPtr = new int;
.
.
.
delete pIntPtr;
我的问题:每个进程是堆内存吗?
如果是,
只有当进程处于运行状态时才可能发生内存泄漏。
如果否,
然后它意味着操作系统能够将数据保留在某个内存中。如果是这样,是否有办法通过另一个进程访问此内存。这也可能成为进程间通信的一种方式。
我想回答我的问题是肯定的。请提供宝贵的反馈意见。
答案 0 :(得分:16)
在几乎每个当前使用的系统上,堆内存都是按进程进行的。在没有受保护内存的旧系统上,堆内存是系统范围的。 (简而言之,这就是受保护的内存所做的:它使您的堆和堆栈对您的进程保密。)
所以在任何现代系统的示例代码中,如果进程在delete pIntPtr
被调用之前终止,pIntPtr
仍将被释放(尽管它的析构函数,而不是int有一个,不会叫。)
请注意,受保护的内存是一个实现细节,不是 C ++或C标准的一个功能。一个系统可以在进程之间自由共享内存(现代系统只是不,因为这是攻击者向你提供屁股的好方法。)
答案 1 :(得分:3)
在大多数现代操作系统中,每个进程都有自己的堆,只能由该进程访问,并在进程终止后回收 - {private}堆通常由new
使用。此外,可能还有一个全局堆(例如,查看Win32 GlobalAlloc()
族函数),它在进程之间共享,为系统运行时持久存在,实际上可用于进程间通信。
答案 2 :(得分:2)
通常,对进程的内存分配发生在比堆管理更低的级别。
换句话说,堆是在操作系统为进程提供的进程虚拟地址空间内构建的,并且对该进程是私有的。当进程退出时,操作系统将回收此内存。
请注意,C ++并未强制要求这一点,这是C ++运行的执行环境的一部分,因此ISO标准并未规定此行为。我正在讨论的是常见的实施。
在UNIX中,brk
和sbrk
系统调用用于从操作系统分配更多内存以扩展堆。然后,一旦完成该过程,所有这些内存都将返回给操作系统。
获得可以超过进程的内存的正常方法是使用共享内存(在UNIX类型的操作系统下,不确定Windows)。 可以导致泄漏,但会导致更多系统资源而不是处理资源。
答案 3 :(得分:1)
有些特殊用途的操作系统不会在进程退出时回收内存。如果你的目标是这样的操作系统,你可能知道。
大多数系统不允许您访问另一个进程的内存,但是再次......有一些独特的情况,这是不正确的。
C ++标准处理这种情况,没有声明如果你没有释放内存然后退出将会发生什么,也不会在你试图访问未明确访问的内存时发生什么。这是“未定义行为”意味着什么的本质,并且是指针“无效”的核心。有两个问题不仅仅是这两个问题,但这两个问题起了作用。
答案 4 :(得分:0)
通常,当进程终止时,操作系统将回收任何泄漏的内存。
由于这个原因,我认为C ++程序员在进程退出之前永远不会显式释放所需的任何内存,这是可以的。例如,流程中的任何“单身人士”通常不会被明确释放。
这种行为可能是O / S特定的(虽然它对Windows和Linux都是如此):理论上不是C ++标准的一部分。
答案 5 :(得分:0)
出于实际目的,您的问题的答案是肯定的。现代操作系统通常会在该进程关闭时释放由进程分配的内存。但是,依靠这种行为是一种非常粗暴的做法。即使我们可以确信操作系统将始终以这种方式运行,但代码仍然很脆弱。如果某些无法释放内存的函数突然被重用于其他目的,则可能会转换为应用程序级内存泄漏。
然而,从道德上讲,这个问题的性质和发布的例子要求我和你的团队指出RAII。
int *pIntPtr = new int;
...
delete pIntPtr;
这段代码充满了内存泄漏。如果[...]抛出任何内容,则会发生内存泄漏。有几种解决方案:
int *pIntPtr = 0;
try
{
pIntPtr = new int;
...
}
catch (...)
{
delete pIntPtr;
throw;
}
delete pIntPtr;
使用nothrow的第二种解决方案(不一定比第一种好,但允许在定义时合理初始化pIntPtr):
int *pIntPtr = new(nothrow) int;
if (pIntPtr)
{
try
{
...
}
catch (...)
{
delete pIntPtr;
throw;
}
delete pIntPtr;
}
简单的方法:
scoped_ptr<int> pIntPtr(new int);
...
在这个最后也是最好的例子中,没有必要在pIntPtr上调用delete,因为这是自动完成的,无论我们如何退出这个块(欢呼RAII和智能指针)。