为什么在重新分配失败后,先前分配的内存无法访问?

use*_*140 0 c c++ realloc segmentation-fault

我需要为进程分配所有可用内存,以便实现系统服务的测试.测试(以及其他)需要耗尽所有可用资源,尝试呼叫以及检查特定结果.

为了做到这一点,我写了一个循环,重新分配一块内存,直到,realloc返回null,然后使用最后一个好的分配,然后削减上一个成功数量和最后一个不成功的数量之间的差异,直到不成功的数量为1个字节大于上一个成功数量,保证消耗所有可用内存.

我写的代码如下(调试打印也包括在内)

#include <stdio.h>
#include <malloc.h>
int main(void)
{
    char*       X;
    char*       lastgood = NULL;
    char*       toalloc = NULL;
    unsigned int    top = 1;    
    unsigned int    bottom = 1; 
    unsigned int    middle;     
    do              
    {               
        bottom = top;
        lastgood = toalloc;     
        top = bottom*2;                 
        printf("lastgood = %p\ntoalloc = %p\n", lastgood, toalloc); 
        if (lastgood != NULL)           
            printf("*lastgood = %i\n", *lastgood);      
        toalloc = realloc(toalloc, top);    
        printf("lastgood = %p\ntoalloc = %p\n", lastgood, toalloc); 
        if (toalloc == NULL && lastgood != NULL)        
            printf("*lastgood = %i\n", *lastgood);  //segfault happens here 
    }while(toalloc != NULL);                    
    do                          
    {                           
        if (toalloc != NULL) lastgood = toalloc;        
        else toalloc = lastgood;                
        middle = bottom+(top - bottom)/2;           
        toalloc = realloc(toalloc, middle);         
        if (toalloc == NULL) top = middle;          
        else bottom = middle;               
    }while(top - bottom > 1);               
    if (toalloc != NULL) lastgood = toalloc;                
        X = lastgood;
//make a call that attempts to get more memory
    free(X);
}
Run Code Online (Sandbox Code Playgroud)

根据realloc的联机帮助页,如果返回null,则realloc不会销毁先前的地址.即便如此,当toalloc从realloc接收NULL时,此代码在尝试打印lastgood时会导致段错误.为什么会发生这种情况,是否有更好的方法来获取未分配内存的确切数量?

我在glibc上运行它,在内核3.11.x的ubuntu上运行它

mcl*_*fix 5

您没有检查top溢出的值.这就是它的价值:

2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
131072
262144
524288
1048576
2097152
4194304
8388608
16777216
33554432
67108864
134217728
268435456
536870912
1073741824
2147483648
0
Run Code Online (Sandbox Code Playgroud)

在最后一个之前realloc(),top的新值再次为0(实际上2^32但不适合32位),这似乎导致内存块实际解除分配.


尝试分配最大连续块不是一个好主意.用户进程看到的内存映射已经为共享库分配了一些块,以及当前进程的实际代码和数据.除非您想知道可以分配的最大连续内存块,否则可以在单个块中尽可能多地分配.当你到达那个,用不同的指针做同样的事情,并继续这样做,直到你真的用完了内存.请注意,在64位系统中,您只能在一个系统中获得所有可用内存malloc()/realloc().正如我刚才所看到的,malloc()在64位系统4GB中,即使你可以发出多个mallocs()并且仍然在每个调用中都成功,在一次调用中会分配多达内存.

我在几天前给出的答案中描述了在32位Linux系统中看到的用户进程内存映射的可视化: 内核空间是否映射到Linux x86上的用户空间?

我已经想出了这个程序,可以"吃掉"所有的内存:

#include <stdio.h>
#include <malloc.h>

typedef struct slist
{
  char *p;
  struct slist *next;
} TList;

int main(void)
{
  size_t nbytes;
  size_t totalbytes = 0;
  int i = 0;
  TList *list = NULL, *node;

  node = malloc (sizeof *node);
  while (node)
  {
    node->next = list;
    list = node;
    nbytes = -1; /* can I actually do this? */ 
    node->p  = malloc(nbytes);  
    while (nbytes && !node->p)
    {
      nbytes/=2;
      node->p = malloc(nbytes);
    }
    totalbytes += nbytes + sizeof *node;
    if (nbytes==0)
      break;
    i++;
    printf ("%8d", i);
  }
  printf ("\nBlocks allocated: %d. Memory used: %f GB\n", 
                 i, totalbytes/(1024*1048576.0));
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

执行在32位Linux系统中产生这些值:

 1       2       3       4       5       6       7       8       9      10
11      12      13      14      15      16      17      18      19      20
21      22      23      24      25      26      27      28      29      30
31      32      33      34      35      36      37      38      39      40
41      42      43      44      45      46      47      48      49      50
51      52      53
Blocks allocated: 53. Memory used: 2.998220 GB
Run Code Online (Sandbox Code Playgroud)

非常接近32位Linux系统的3GB限制.在64位Linux系统上,我已经达到300004GB每个系统的块,并且还在计算中.我真的不知道Linux是否可以分配那么多内存,或者这是我的错误.根据,最大的虚拟地址空间是128TB(这将是32768 4GB块)


更新:事实上,确实如此.我已经在64位的盒子上运行了这个程序,并且在110074成功分配了块后,分配的内存总量已经达到了131071.578884 GB.每个操作malloc()都可以分配多个4 GB操作,但是当达到时115256 GB,它已经开始分配2 GB,然后当它达到123164 GB分配时,它开始分配到1GB每个操作malloc().这种进展在合理上倾向于131072 GB,但它实际上会稍早停止,131071.578884 GB因为这个过程,它的数据和共享库使用几KB的内存.

在此输入图像描述