Чтение блог Мартина Sustrick о проблемах, связанных с предотвращением "поведения undefined" на С++, vs C, в частности, проблемного с malloc() из-за нехватки памяти, мне напомнили о многих, много раз я был расстроен, чтобы знать, что делать в таких случаях.
В виртуальных системах такие условия редки, но на встроенных платформах или когда ухудшение производительности, связанное с ударом виртуальной системы, приравнивается к отказу, как и случай Мартина с ZeroMQ, я решил найти подходящее решение и сделал.
Я хотел спросить читателей StackOverflow, если они пробовали этот подход, и каков был их опыт.
Решение состоит в том, чтобы выделить кусок резервной памяти из кучи с вызовом malloc() в начале программы, а затем использовать этот пул резервной памяти, чтобы предотвратить исчерпание памяти, когда и когда это произойдет. Идея состоит в том, чтобы предотвратить капитуляцию в пользу упорядоченного отступления (я вчера читал отчеты Kesselring 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;
}