gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-04 05:40:17 27 4
gpt4 key购买 nike

我需要为一个进程分配所有可用的内存,以实现对系统服务的测试。该测试(以及其他)需要用尽所有可用资源、尝试调用并检查特定结果。

为了做到这一点,我写了一个循环,重新分配一 block 内存直到,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的manpage,如果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

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


尝试分配最大的连续 block 不是一个好主意。用户进程看到的内存映射已经为共享库分配了一些 block ,以及当前进程的实际代码和数据。除非您想知道可以分配的最大连续内存块,否则方法是在单个 block 中分配尽可能多的内存块。当你到达那里时,用不同的指针做同样的事情,并继续这样做,直到你真的用完内存。考虑到在 64 位系统中,您无法仅在一次 malloc()/realloc() 中获得所有可用内存。正如我刚刚看到的,64 位系统中的 malloc() 在一次调用中分配了高达 4G​​B 的内存,即使您可以发出多个 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 个 block ,每个 block 4G​​B,并且还在继续计数。我真的不知道 Linux 是否可以分配那么多内存,或者这是我的错误。根据 this ,最大虚拟地址空间为 128TB(即 32768 4G​​B block )


更新:事实上,就是这样。我在 64 位机器上运行这个程序,在 110074 成功分配 block 后,分配的内存总量为 131071.578884 GB。每个 malloc() 每次操作最多可以分配 4 GB,但是当达到 115256 GB 时,它就开始分配了到 2 GB,然后当它达到分配的 123164 GB 时,它开始为每个 malloc() 分配最多 1GB >。渐进式趋向于 131072 GB,但它实际上停止得更早一点,131071.578884 GB 因为这个进程、它的数据和共享库使用了几 KB 的内存。

enter image description here

关于c++ - 为什么在重新分配失败后无法访问先前分配的内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20914395/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com