gpt4 book ai didi

c - 由于内存耗尽而从 NULL == malloc() 恢复的策略

转载 作者:IT王子 更新时间:2023-10-28 23:34:55 26 4
gpt4 key购买 nike

阅读 Martin Sustrick's blog关于防止 C++ 与 C 中的“未定义行为”相关的挑战,特别是 malloc() 由于内存耗尽而失败的问题,我想起了很多很多次,我很沮丧地知道在这种情况下该怎么做案例。

对于虚拟系统,这种情况很少见,但在嵌入式平台上,或者在与虚拟系统相关的性能下降等同于失败的情况下,就像 Martin 在 ZeroMQ 中的情况一样,我决定找到一个可行的解决方案,并且确实做到了。

我想问一下 StackOverflow 的读者是否尝试过这种方法,以及他们的体验如何。

解决方案是在程序开始时调用 malloc() 从堆中分配一 block 备用内存,然后在发生内存耗尽时使用该空闲内存池来避免内存耗尽。这个想法是为了防止投降以支持有序撤退(我昨晚正在阅读 Kesselring's defense of Italy 的帐户),其中错误消息和 IP 套接字等将工作足够长的时间(希望)至少告诉用户发生了什么。

#define SPARE_MEM_SIZE (1<<20)  // reserve a megabyte
static void *gSpareMem;

// ------------------------------------------------------------------------------------------------
void *tenacious_malloc(int requested_allocation_size) {
static int remaining_spare_size = 0; // SPARE_MEM_SIZE;
char err_msg[512];
void *rtn = NULL;

// attempt to re-establish the full size of spare memory, if it needs it
if (SPARE_MEM_SIZE != remaining_spare_size) {
if(NULL != (gSpareMem = realloc(gSpareMem, SPARE_MEM_SIZE))) {
remaining_spare_size = SPARE_MEM_SIZE;
// "touch" the memory so O/S will allocate physical memory
meset(gSpareMem, 0, SPARE_MEM_SIZE);
printf("\nSize of spare memory pool restored successfully in %s:%s at line %i :)\n",
__FILE__, __FUNCTION__, __LINE__);
} else {
printf("\nUnable to restore size of spare memory buffer.\n");
}
}
// attempt a plain, old vanilla malloc() and test for failure
if(NULL != (rtn = malloc(requested_allocation_size))) {
return rtn;
} else {
sprintf(err_msg, "\nInitial call to malloc() failed in %s:%s at line %i",
__FILE__, __FUNCTION__, __LINE__);
if(remaining_spare_size < requested_allocation_size) {
// not enough spare storage to satisfy the request, so no point in trying
printf("%s\nRequested allocaton larger than remaining pool. :(\n\t --- ABORTING --- \n", err_msg);
return NULL;
} else {
// take the needed storage from spare memory
printf("%s\nRetrying memory allocation....\n", err_msg);
remaining_spare_size -= requested_allocation_size;
if(NULL != (gSpareMem = realloc(gSpareMem, remaining_spare_size))) {
// return malloc(requested_allocation_size);
if(NULL != (rtn = malloc(requested_allocation_size))) {
printf("Allocation from spare pool succeeded in %s:%s at line %i :)\n",
__FILE__, __FUNCTION__, __LINE__);
return rtn;
} else {
remaining_spare_size += requested_allocation_size;
sprintf(err_msg, "\nRetry of malloc() after realloc() of spare memory pool "
"failed in %s:%s at line %i :(\n", __FILE__, __FUNCTION__, __LINE__);
return NULL;
}
} else {
printf("\nRetry failed.\nUnable to allocate requested memory from spare pool. :(\n");
return NULL;
}
}
}
}
// ------------------------------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[]) {
int *IntVec = NULL;
double *DblVec = NULL;
char *pString = NULL;
char String[] = "Every good boy does fine!";

IntVec = (int *) tenacious_malloc(100 * sizeof(int));
DblVec = (double *) tenacious_malloc(100 * sizeof(double));
pString = (char *)tenacious_malloc(100 * sizeof(String));

strcpy(pString, String);
printf("\n%s", pString);


printf("\nHit Enter to end program.");
getchar();
return 0;
}

最佳答案

最佳策略是针对无需分配即可工作的代码。特别是,对于一个正确、健壮的程序,所有故障路径必须是无故障情况的,这意味着您不能在故障路径中使用分配。

我的偏好是尽可能避免在操作开始后进行任何分配,而是在操作开始之前确定所需的存储空间并全部分配。这可以大大简化程序逻辑并使测试更加容易(因为您必须测试一个可能的故障点)。当然,它也可以在其他方面更昂贵;例如,您可能需要对输入数据进行两次传递以确定您需要多少存储空间,然后使用该存储空间进行处理。

关于您在 malloc 失败时预先分配一些紧急存储以供使用的解决方案,基本上有两个版本:

  1. 只需在紧急存储上调用 free,然后希望 malloc 之后再次工作。
  2. 检查您自己的包装层,以便包装层可以直接使用紧急存储而无需释放它。

第一种方法的优点是即使标准库和第三方库代码也可以使用紧急空间,但它的缺点是释放的存储空间可能会被其他进程或您自己进程中的线程抢走它。如果您确定内存耗尽将来自耗尽虚拟地址空间(或进程资源限制)而不是系统资源,并且您的进程是单线程的,那么您不必担心比赛,您可以相当安全假设这种方法会奏效。但是,一般来说,第二种方法更安全,因为您有绝对的保证您可以获得所需的紧急存储量。

我不太喜欢这两种方法,但它们可能是你能做的最好的。

关于c - 由于内存耗尽而从 NULL == malloc() 恢复的策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21172440/

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