微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

阅读 Martin Sustrick’s blog在C,vs C中防止“未定义行为”的挑战,特别是由于内存耗尽而malloc()失败的问题,我被提醒了很多次,我很沮丧地知道该怎么做在这种情况下.

虚拟系统这样的条件是罕见的,但是在嵌入式平台上,或者与虚拟系统相关的性能下降等于失败,马丁与ZeroMQ的情况一样,我决定找到一个可行的解决方案.

如果他们尝试了这种方法,我想问StackOverflow的读者,他们的经验是什么.

解决方案是在程序开始时调用一个malloc()的一堆空闲的内存,然后使用这个备用内存池来排除内存耗尽,何时出现.这个想法是为了防止投机,有利于有序撤退(我正在读取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,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",__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",__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",__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失败,预先分配一些应急存储器就可以使用,基本上有两个版本:

>只需在紧急情况下可以免费通话,那么希望malloc再次起作用.
>通过自己的包装层,让包装层可以直接使用紧急存储,而不用释放它.

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

我不喜欢这些方法之一,但他们可能是你能做的最好的.

原文地址:https://www.jb51.cc/c/113725.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐