每个进程是堆内存吗? (或)不同进程共享的公共内存位置?

时间:2010-06-30 06:54:50

标签: c++ memory-leaks operating-system shared-memory heap-memory

每个进程都可以使用堆内存来存储和共享进程内的数据。每当我们在堆内存中占用一些空间时,我们就有编程规则,我们需要在作业完成后释放它,否则会导致内存泄漏。

int *pIntPtr = new int;
.
.
.
delete pIntPtr;

我的问题:每个进程是堆内存吗?

如果是,

  

只有当进程处于运行状态时才可能发生内存泄漏。

如果否,

  

然后它意味着操作系统能够将数据保留在某个内存中。如果是这样,是否有办法通过另一个进程访问此内存。这也可能成为进程间通信的一种方式。

我想回答我的问题是肯定的。请提供宝贵的反馈意见。

6 个答案:

答案 0 :(得分:16)

在几乎每个当前使用的系统上,堆内存都是按进程进行的。在没有受保护内存的旧系统上,堆内存是系统范围的。 (简而言之,这就是受保护的内存所做的:它使您的堆和堆栈对您的进程保密。)

所以在任何现代系统的示例代码中,如果进程在delete pIntPtr被调用之前终止,pIntPtr仍将被释放(尽管它的析构函数,而不是int有一个,不会叫。)

请注意,受保护的内存是一个实现细节,不是 C ++或C标准的一个功能。一个系统可以在进程之间自由共享内存(现代系统只是,因为这是攻击者向你提供屁股的好方法。)

答案 1 :(得分:3)

在大多数现代操作系统中,每个进程都有自己的堆,只能由该进程访问,并在进程终止后回收 - {private}堆通常由new使用。此外,可能还有一个全局堆(例如,查看Win32 GlobalAlloc()族函数),它在进程之间共享,为系统运行时持久存在,实际上可用于进程间通信。

答案 2 :(得分:2)

通常,对进程的内存分配发生在比堆管理更低的级别。

换句话说,堆是在操作系统为进程提供的进程虚拟地址空间内构建的,并且对该进程是私有的。当进程退出时,操作系统将回收此内存。

请注意,C ++并未强制要求这一点,这是C ++运行的执行环境的一部分,因此ISO标准并未规定此行为。我正在讨论的是常见的实施。

在UNIX中,brksbrk系统调用用于从操作系统分配更多内存以扩展堆。然后,一旦完成该过程,所有这些内存都将返回给操作系统。

获得可以超过进程的内存的正常方法是使用共享内存(在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和智能指针)。