当前位置: 首页 > 知识库问答 >
问题:

在不终止程序的情况下将动态分配的内存返回操作系统

鲁才艺
2023-03-14

我正在开发一个程序,在这个程序中,我使用了大量但有限的内存。内存在不同线程上运行时分配和释放。但是,我注意到程序的内存使用不会保持在指定的范围内。随着时间的推移,它会增加。我编写了以下示例程序来检查内存是否被释放回操作系统。一半分配的内存被释放以检查内存使用是否下降。

int main()
{
    char *p[COUNT];

    for(int i = 0; i < COUNT; i++)
    {
        p[i] = new char[1048576];
        memset (p[i], 0, 1048576);
        printf("%p\n", p[i]);
    }

    printf("done allocating ... \n");

    sleep(10);

    printf("Freeing\n");
    for(int i; i < COUNT; i++)
    {
        delete[] p[i];
    }

    while(1)
        sleep(1);
}

运行程序后,操作系统似乎不会回收释放的页面。分配内存和释放内存后,内存使用情况与linux中的“top”命令中的相同。它只是将这些页面标记为可供同一程序重用的免费页面。在我的程序中,malloc和free在不同的线程上运行。当调用malloc的频率远高于空闲时,这会带来内存管理问题,并且html" target="_blank">进程数据段变得非常大,导致操作系统将页面交换到磁盘。这使得程序和操作系统变得缓慢且无响应。操作系统有没有办法回收释放的内存?

共有2个答案

甄煜
2023-03-14

进程退出后,将回收进程使用的所有内存。操作系统可能会推测性地缓存数据以备不时之需(如Linux Ate My RAM上所述)。每当另一个进程需要内存时,就会释放内存。

编辑:因为您指的是长时间运行的服务器进程,所以您关心的是进程仍在运行时的内存使用情况。我建议使用valgrind作为检测应用程序内存泄漏的工具,使用RAII作为防止内存泄漏的编码技术。注意Linux上的内存使用情况(以及一般情况!)很难测量/解释,ps和top等工具的输出可能具有误导性和不直观性,例如根据此答案。

林鸿飞
2023-03-14

在Linux上,您可以使用mmap(2)获得一些空间(在虚拟内存中)(由malloc或operator new等使用)。然后您可以稍后使用munmap发布它

由于mmap和munmap的成本有点高,所以malloc(因此,通常在malloc之上实现的操作符new)尝试重用以前可用的内存区域,所以不要总是向内核释放内存(低于一个大阈值,可能是128K或更多)。

顺便说一句,proc(5)为内核提供了一个有用的接口来查询事物。对于pid 1234的进程,您可以cat /proc/1234/maps来显示其地址空间内存映射(在进程内部,使用/proc/Self/map

所以你可以编码:

const size_t sz = 1048576;
/// allocating loop
for (i=0; i < 2000 ;i++ ) {
  void* ad = mmap(NULL, sz, PROT_READ|PROT_WRITE, 
                  MMAP_PRIVATE|MMAP_ANONYMOUS,
                  -1, (off_t)0);
  if (ad == MMAP_FAILED)
    { perror("mmap"); exit (EXIT_FAILURE); }
  p[i] = ad;
  memset (p[i], 0, sz); // actually uneeded
}
printf ("done allocating ... \n");
sleep(5);
// freeing loop
printf("Freeing\n");
for (i=0; i < 2000 ;i++ ) {
  if (munmap((void*)p[i], sz)) 
    { perror("munmap"); exit(EXIT_FAILURE); }
  p[i] = nullptr;
}

请注意,使用“匿名映射”(MAP\u ANONYMOUS)的mmap将在成功时提供一个归零的内存区域,因此您不需要使用memset来清除它。

在C中,如果需要,您还可以定义自己的操作符new(调用mmap)和操作符delete(调用munmap)。

另请阅读高级Linux编程。

 类似资料:
  • 问题内容: 我有以下代码: 在发生某些事件之后,我应该停止在的方法中声明的操作,该方法实现。 我怎样才能做到这一点?我无法关闭执行器,只能撤消我的定期任务。我可以用吗?如果可以的话,请告诉我它将如何工作。 问题答案: 使用。该是你的任务的处理。您需要取消此任务,它将不再执行。 实际上,是签名,并将其与参数一起使用将导致当前正在运行的执行线程被调用中断。如果线程在阻塞的可中断调用(例如)中等待,则会

  • 问题内容: 我想测试在32位操作系统上是否可以通过乘法进程使用超过4GB的内存(我的:具有1GB内存的Ubuntu)。 因此,我编写了一个小程序,该程序的malloc小于1GB,并对该数组进行了一些操作,并运行了该程序的5个实例。 事实是,我怀疑OS杀死了其中的4个,只有一个幸存下来并显示为“ PID:我完成了”。 (我已经尝试过使用小型阵列并进行5次打印,而且当我使用TOP查看正在运行的进程时,

  • 我一直在玩流,然后我注意到当我执行以下操作时,它不会在控制台中产生输出: 我认为这是因为是一个非终止流方法,应该使用而不是来终止流并生成结果: 然而,是否有一种方法可以‘提前’终止流,使用一个自定义的终止方法(函数接口),它除了终止流之外什么都不做?..有没有一个适当的方法来利用Java现有的东西来做到这一点? 我知道我可以这样做: 但那感觉很浪费。

  • 问题内容: 当我在Linux上使用顶级终端程序时,看不到免费的结果。 我的期望是: 免费地图和清单。 我可以在顶部看到内存使用情况(Linux函数),或者 变得比过去更小。 睡眠开始了。 程序退出。 但是,只有在程序结束时,内存使用量才会变小。 您能解释一下自由功能的逻辑吗? 下面是我的代码。 谢谢。 问题答案: 内存分配到堆上。 当您在程序中请求一些内存时(使用new()或malloc()等),

  • 问题内容: 考虑以下程序: 为什么它在本地终止而不在Playground终止?我的程序终止是否依赖未定义的行为? 问题答案: 该代码不能提供太多保证。它几乎完全依赖于围绕未定义行为的实现细节。 在大多数多线程系统中,不能保证一个线程中的更改不会出现障碍。您有一个goroutine,可以在另一个处理器上运行,总共将一个值写入一个没有人保证读取的变量。 将可以很容易地重写,因为从未有一个保证该变量的任

  • #include <stdio.h> #include <malloc.h> int main(void) { char *p[10]; int i = 0; for (i = 0; i < sizeof(p)/sizeof(p[0]); i++) { p[i] = malloc(100000);