Linux中的new/delete,malloc/free大内存块

3
我们有一个运行着许多CORBA服务器进程的Linux系统(kubuntu 7.10)。服务器软件使用glibc库进行内存分配。该Linux PC有4G物理内存。为了速度原因,已禁用交换。
当收到处理数据的请求时,其中一个服务器进程会分配一个大型数据缓冲区(使用标准C++操作符“new”)。缓冲区大小根据许多参数而变化,但通常约为1.2G字节。它最多可达约1.9G字节。当请求完成后,使用“delete”释放缓冲区。
如果连续的请求分配相同大小的缓冲区或者请求分配的大小小于之前的请求,则这种情况可以正常工作。内存似乎被正确释放,否则缓冲区分配尝试将在仅几个请求后失败。无论如何,我们可以使用诸如KSysGuard等工具看到每个请求的缓冲区内存被分配和释放。
当请求需要比之前更大的缓冲区时,问题就出现了。在这种情况下,操作符“new”会抛出异常。好像从第一次分配中释放的内存不能重新分配,即使有足够的空闲物理内存也是如此。
如果我在第一次操作后杀死并重新启动服务器进程,那么对于更大的缓冲区大小的第二个请求将成功。即杀死进程似乎完全将释放的内存返回给系统。
有人能解释一下这里可能发生了什么吗?这可能是某种碎片化或映射表大小问题吗?我正在考虑用malloc/free替换new/delete,并使用mallopt调整内存向系统释放的方式。
顺便说一句 - 我不确定它是否与我们的问题相关,但服务器使用在每个处理请求上创建和销毁的Pthreads。
3个回答

4
如果这是一台32位机器,您将拥有3Gb的地址空间可供使用 - 其中1Gb为内核保留。其中相当多的地址空间将被共享库、exe文件、数据段等占用。您应该查看/proc/pid/maps以查看地址空间的布局。
物理地址空间有多少可用很难说,所有系统进程、内核和其他进程都会占用它。假设它们的总和不超过1Gb,您仍然有3Gb可用。
可能发生的情况是碎片化:
0Gb 3Gb ---------------------~------------------------------------ |Stuff | Heap,1.2Gb allocated stuff | free heap | Stack| ---------------------~------------------------------------
然后您释放了大对象,但在之间分配了一些其他内存,使您得到以下结果:
0Gb 3Gb ---------------------~------------------------------------------ |Stuff | Heap,1.2Gb free |small object(s) | free heap | Stack| ---------------------~------------------------------------------
如果现在尝试分配更大的对象,则它不适合于免费的1.2Gb空间中,并且也可能不适合于free heap空间,因为那里可能没有足够的空间。
如果您正在大量使用堆栈,那么可能是堆栈增长并占用本来可以用于堆空间的空间 - 尽管默认情况下,大多数发行版将堆栈限制为8-10Mb。
使用malloc/realloc将无法解决此问题。但是,如果您知道所需的最大对象的大小,则可以在启动时保留该大小。该块应该永远不会被释放/删除,而应该重新使用。虽然可用于其他对象的空间将变小,但是否会在其他地方遇到麻烦很难说。

0
非常感谢您的回复。 进一步的调查表明,碎片化确实是问题所在。 当第一个请求到达时,保留我们将需要的最大缓冲区,并将该缓冲区用于后续请求似乎是可行的。

0

您的地址空间不足,因此没有单个块足够大以满足您的分配。

解决方法是运行64位操作系统-毕竟,这是21世纪!

当然,您需要重新测试应用程序以确保其与64位兼容(并重新编译等),但从长远来看这是有意义的。现在4G对于服务器来说并不是很多;一个相当适度的服务器拥有16-32G。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接