即使仍有足够的内存,内存分配也会失败

Memory allocation failed even when there is still enough memory

本文关键字:内存 分配 失败      更新时间:2023-10-16

我正在Linux上工作(确切地说是ubuntu 13.04),目前我有一个问题:为什么即使仍然有足够的内存,内存分配也会失败?

我今天写了一个简单的测试应用程序,在运行这个测试应用程序时遇到了这个问题。 以下是我用来进行测试的代码片段:

     #include <stdio.h>
     #include <unistd.h>
     #include <list>
     #include <vector>
     #include <strings.h>
     using namespace std;
     unsigned short calcrc(unsigned char *ptr, int count)
     {
        unsigned short crc;
        unsigned char i;
        //high cpu-consumption code
        //implements CRC algorithm: Cylic 
        //Redundancy code              
     }

     void* CreateChild(void* param){
         vector<unsigned char*>  MemoryVector;
         pid_t PID = fork();
         if (PID == 0){
             const int MEMORY_TO_ALLOC =  1024 * 1024;
             unsigned char* buffer = NULL;
             while(1){
                 buffer  = NULL;
                 try{
                     buffer = new unsigned char [MEMORY_TO_ALLOC]();
                     calcrc(buffer, MEMORY_TO_ALLOC );
                     MemoryVector.push_back(buffer);
                 } catch(...){
                     printf("an exception was thrown!n");
                     continue;
                 } //try ... catch
             } //while  
          } // if pid == 0
      return NULL;
      }
    int main(){
        int children = 4;
        while(--children >= 0){
            CreateChild(NULL);
        };
        while(1) sleep(3600);
        return 0;
    }

在我的测试中,当有大约 220M RAM 可用时,上面的代码开始引发异常。从那一刻起,看起来应用程序无法再获得更多内存因为TOP命令显示的可用内存仍然在210M以上。那么为什么会这样呢?

更新
1. 软件和硬件信息
RAM是4G,交换大约是9G字节。运行"uname -a"给出: Linux steve-ThinkPad-T410 3.8.0-30-generic #44-Ubuntu SMP 周四 8月 22 日 20:54:42 UTC 2013 i686 i686 i686 i686 GNU/Linux
2. 测试期间的统计数据

      Right after Test App Starts Throwing Exception
      steve@steve-ThinkPad-T410:~$ free
                    total       used       free     shared    buffers     cached
       Mem:       3989340    3763292     226048          0       2548      79728
       -/+ buffers/cache:    3681016     308324
       Swap:      9760764    9432896     327868
      10 minutes after Test App Starts Throwing Exception
      steve@steve-ThinkPad-T410:~$ free
                    total       used       free     shared    buffers     cached
       Mem:       3989340    3770808     218532          0       3420      80632
       -/+ buffers/cache:    3686756     302584
       Swap:      9760764    9436168     324596

      20 minutes after Test App Starts Throwing Exception
      steve@steve-ThinkPad-T410:~$ free
                    total       used       free     shared    buffers     cached
       Mem:       3989340    3770960     218380          0       4376     104716
       -/+ buffers/cache:    3661868     327472
       Swap:      9760764    9535700     225064
      40 minutes after Test App Starts Throwing Exception
      steve@steve-ThinkPad-T410:~$ free
                    total       used       free     shared    buffers     cached
       Mem:       3989340    3739168     250172          0       2272     139108
       -/+ buffers/cache:    3597788     391552
       Swap:      9760764    9556292     204472

可能是您的地址空间中不再有 1MB 的顺序内存页。 您有可用空间碎片。

在我的测试过程中,当内存约为 220M 时,上面的代码开始引发异常。从那一刻起,应用程序似乎无法再获得更多内存,因为 TOP 命令显示的可用内存仍然高于 210M。那么为什么会这样呢?

top 的输出每 N 秒更新一次(已配置),并且不会真正显示当前状态。

另一方面,内存分配速度超快。

发生的情况是你的程序消耗内存,并且在某个时候(当顶部显示200 Mb可用时)它开始失败。

您在 x86-32 上运行,因此您的进程是 32 位的。即使有更多的内存+交换,它们也会受到地址空间的限制,运行:

grep “HIGHMEM” /boot/config-`uname -r`
grep “VMSPLIT” /boot/config-`uname -r`

以查看内核的配置方式。

也许您的 4 个子进程仅限于 3G,并且正在使用 12G + 其他进程 ~700M 来达到您看到的数字。

编辑:

因此,您的内核被配置为为每个用户空间进程提供 3G 的地址空间,其中一些将与程序、库和初始运行时内存(由于分叉而共享)一起占用。

因此,您有 4 个孩子每人使用 ~3G - ~12G + ~780M 的其他程序。一旦孩子们开始报告错误,就剩下大约 220M 可用空间。

您可以只运行另一个子进程,也可以重新安装 AND64/x86-64 版本的 Ubuntu,其中每个进程将能够分配更多内存。