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上运行它
您没有检查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系统上,我已经达到30000了4GB每个系统的块,并且还在计算中.我真的不知道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的内存.
