首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >堆内存分配

堆内存分配
EN

Stack Overflow用户
提问于 2015-08-22 08:13:39
回答 6查看 1.6K关注 0票数 15

如果我使用malloc()在程序中动态分配内存,但在程序运行时不释放内存,那么程序终止后会释放动态分配的内存吗?

或者如果它没有被释放,并且我一次又一次地执行相同的程序,它会每次分配不同的内存块吗?如果是这样的话,我该如何释放这些记忆呢?

注意:我能想到的一个答案是重新启动正在执行程序的机器。但是,如果我在远程机器上执行程序,而重新启动不是一种选择?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2015-08-25 07:46:06

简短回答:一旦进程终止,任何合理的操作系统都将释放该进程分配的所有内存。因此,当您多次重新启动进程时,内存分配不会累积。

进程和内存管理通常是操作系统的职责,因此在进程终止后是否释放分配的内存实际上取决于操作系统。不同的操作系统可以以不同的方式处理内存管理。

尽管如此,任何合理的操作系统(特别是多任务操作系统)都将释放进程终止后分配的所有内存。

我认为这背后的原因是操作系统必须能够优雅地处理不规则的情况:

  • 恶意程序(例如那些没有故意释放内存的程序,希望影响它们运行的系统)
  • 异常程序终止(即程序意外结束,因此可能没有机会显式地free其动态分配的内存本身)

任何有价值的操作系统都必须能够处理这种情况。它必须将系统的其他部分(例如,自身和其他正在运行的进程)与错误的进程隔离开来。否则,进程的内存泄漏将传播到系统。这意味着操作系统会泄漏内存(通常被认为是错误)。

保护系统免受内存泄漏的一种方法是确保一旦进程结束,它使用的所有内存(可能还有其他资源)都会被释放。

票数 19
EN

Stack Overflow用户

发布于 2015-08-22 08:18:44

当程序终止时,分配的任何内存都应该被释放,不管是静态的还是动态的。这方面的主要例外是,如果进程被分叉到另一个进程。

如果没有显式地free任何malloc内存,它将一直保持分配,直到进程终止为止。

票数 8
EN

Stack Overflow用户

发布于 2015-08-28 23:46:36

即使您的操作系统在exit()上进行了清理。要退出的syscall通常由exit()函数包装。下面是一些伪代码,来自于研究几个libc实现,以演示在main()周围发生的可能导致问题的情况。

代码语言:javascript
复制
//unfortunately gcc has no builtin for stack pointer, so we use assembly
#ifdef __x86_64__
   #define STACK_POINTER "rsp"
#elif defined __i386__
   #define STACK_POINTER "esp"
#elif defined __aarch64__
   #define STACK_POINTER "x13"
#elif defined __arm__
   #define STACK_POINTER "r13"
#else
  #define STACK_POINTER "sp" //most commonly used name on other arches
#endif
char **environ;
void exit(int);
int main(int,char**,char**); 
_Noreturn void _start(void){ 
   register long *sp __asm__( STACK_POINTER ); 
   //if you don't use argc, argv or envp/environ, just remove them
   long argc = *sp;
   char **argv = (char **)(sp + 1);
   environ = (char **)(sp + argc + 1);
   //init routines for threads, dynamic linker, etc... go here
   exit(main((int)argc, argv, environ));
   __builtin_unreachable(); //or for(;;); to shut up compiler warnings
}

注意,exit是使用main的返回值调用的。在没有动态链接器或线程的静态构建中,exit()可以是一个直接内联的syscall(__NR_exit,main(...));但是,如果您的libc使用一个包装器来执行*_fini()例程(大多数libc实现都是这样),那么在main()终止后仍然有一个函数可调用。

恶意程序可能会LD_PRELOAD、exit()或它调用的任何例程,并将其转换为一种永远不会释放内存的僵尸进程。

即使在free()之前执行exit(),进程仍然会消耗一些内存(基本上是可执行文件的大小,在某种程度上是其他进程不使用的共享库),但是一些操作系统可以在相同程序的后续负载中重用非malloc()ed内存,这样您就可以在没有注意到僵尸的情况下运行数月。

FWIW,大多数libc实现都有某种exit()包装,除了dietlibc (作为静态库构建时)和我只在Puppy上发布的部分静态libc.h。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32153924

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档