我需要为进程分配所有可用内存,以便实现系统服务的测试。测试(以及其他测试)需要耗尽所有可用资源,尝试呼叫以及检查特定结果。
为了做到这一点,我写了一个循环来重新分配一块内存,直到,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);
}
根据realloc的联机帮助页,如果返回null,则realloc不会销毁先前的地址。即便如此,当toalloc从realloc接收NULL时,此代码在尝试打印lastgood时会导致段错误。为什么会发生这种情况,是否有更好的方法来获取未分配内存的确切数量?
我在glibc上运行它,在内核3.11.x
的ubuntu上运行答案 0 :(得分: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
在最后一个realloc()
之前,top的新值再次为0(实际为2^32
但不适合32位),这似乎导致内存块实际解除分配。
尝试分配最大连续块不是一个好主意。用户进程看到的内存映射已经为共享库分配了一些块,以及当前进程的实际代码和数据。除非您想知道可以分配的最大连续内存块,否则可以在单个块中尽可能多地分配。当你到达那个,用不同的指针做同样的事情,并继续这样做,直到你真的用完了内存。请注意,在64位系统中,您只能在一个malloc()/realloc()
中获得所有可用内存。正如我刚才所见,64位系统中的malloc()
在一次调用中分配最多4GB
个内存,即使您可以发出多个mallocs()
并且仍然在每个调用中成功。
我在几天前的答案中描述了在32位Linux系统中看到的用户进程内存映射的视觉效果: Is kernel space mapped into user space on 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;
}
执行在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
非常接近32位Linux系统的3GB限制。在64位Linux系统上,我已经达到30000
个4GB
块,并且还在计算中。我真的不知道Linux是否可以分配那么多内存,或者这是我的错误。根据{{3}},最大虚拟地址空间为128TB(即32768
4GB
块
更新:事实上,确实如此。我已经在64位的盒子上运行了这个程序,并且在110074
成功分配了块后,分配的内存总量为131071.578884 GB
。每个malloc()
每个操作都能分配4 GB
,但到达115256 GB
时,它已开始分配最多2 GB
,然后达到123164 GB
时1GB
1}}已分配,它开始每malloc()
分配131072 GB
。这种进展在合理上倾向于131071.578884 GB
,但它实际上会稍早停止,{{1}}因为进程,它的数据和共享库使用了几KB的内存。
答案 1 :(得分:1)
我认为getrlimit()
是您新问题的答案。这是手册页http://linux.die.net/man/2/getrlimit
您可能对RLIMIT_STACK
感兴趣。请查看手册页。
答案 2 :(得分:0)
第一部分将替换为以下内容。
char *p;
size_t size = SIZE_MAX;//SIZE_MAX : #include <stdint.h>
do{
p = malloc(size);
size >>= 1;
}while(p==NULL);