c memory realloc

realloc string



¿Cómo manejar el realloc cuando falla debido a la memoria? (8)

  1. Descubra cómo el marco de la aplicación maneja un OOM. Muchos simplemente no manejarán un OOM. La mayoría de las veces, un marco no funcionará correctamente en condiciones de RAM sin memoria libre, a menos que diga de forma clara e inequívoca en algún lugar que lo hará. Si el marco no maneja un OOM y es multiproceso (muchos lo son hoy en día), un OOM será el final del programa en muchos casos. Incluso si no es multiproceso, todavía puede estar cerca de colapsar. Si sale del proceso o el marco puede ser un punto discutible; una salida inmediata predecible puede ser un poco mejor que un choque en algún punto semi-aleatorio en un futuro cercano.

  2. Si está utilizando una agrupación de sub-memoria de propósito especial separada (es decir, no es su malloc habitual) para un conjunto bien definido de operaciones que solo está restringido en el uso de memoria por OOM (es decir, la operación actual se retrotrae o se cancela de forma limpia) OOM para el conjunto de sub-memoria, no todo el proceso o el conjunto de memoria principal, y ese subgrupo tampoco lo utiliza el marco de la aplicación, o si su marco y el TODO del resto de la aplicación están diseñados para mantenerlos significativos el estado y la operación continuada en condiciones de RAM no libre (es raro pero no desconocido en el modo kernel y en algunos tipos de programación de sistemas) puede ser correcto devolver un código de error en lugar de bloquear el proceso.

  3. Idealmente, la mayor parte de las asignaciones de memoria (o incluso más idealmente todas las asignaciones) para una parte del procesamiento debe asignarse tan pronto como sea posible en el procesamiento, idealmente antes de que comience correctamente, para minimizar los problemas de pérdida de integridad de datos y / o la cantidad de Codificación de retrotracción requerida si falla. En la práctica muchas veces, para ahorrar tiempo y costos de programación en proyectos, para preservar la integridad de los datos, las aplicaciones dependen de las transacciones de la base de datos y requieren que el usuario / persona de soporte detecte un bloqueo de la GUI (o un bloqueo del servidor) y reinicie la aplicación cuando esté fuera de servicio. se producen errores de memoria, en lugar de estar escritos para hacer frente y deshacer en cualquiera y todos los miles de posibles situaciones de OOM de la mejor manera posible. Luego, los esfuerzos se centran en tratar de limitar la exposición de la aplicación a situaciones de sobrecarga, que pueden incluir validación adicional y límites en el tamaño de los datos y conexiones y consultas simultáneas.

  4. Incluso si verifica cuánta memoria se informa como disponible, a menudo, otro código puede asignar o liberar memoria como usted lo hace, cambiando la base de su comprobación de memoria y posiblemente llevando a OOM. Por lo tanto, verificar la RAM libre disponible antes de asignar no suele ser una solución confiable al problema de asegurarse de que su aplicación funcione dentro de los límites de RAM disponibles y mantenga la integridad de los datos lo suficiente para satisfacer a los usuarios.

  5. La mejor situación es saber cuánta memoria necesita su aplicación en todos los casos posibles, incluidos los gastos generales del marco, y mantener esa cifra dentro de la cantidad de RAM disponible para su aplicación, pero los sistemas a menudo son tan complicados con las dependencias externas que dictan Tamaño de los datos para lograr esto puede ser poco realista.

La prueba de ácido, por supuesto, es si está satisfaciendo a los usuarios lo suficiente a través de un alto tiempo de actividad y la pérdida de datos, la pérdida o la falla de los datos. En algunos casos, una aplicación que tenga un proceso de monitoreo para reiniciarla si se bloquea es útil.

En cuanto a realloc:

Verifique el valor de retorno de realloc - póngalo en una variable temporal. Solo importa si es NULL si el nuevo tamaño solicitado era> 0. En otros casos, colóquelo en su variable no temporal:

p.ej

void* temp = realloc(m->data, m->max * sizeof(void*)); if (m->max!=0&&temp==NULL) { /* crash or return error */ } m->data =(void**)temp;

EDITAR

Se cambió "la mayoría de los casos" por "muchos casos" en (1).

Reconozco que ha dicho que debe asumir que "se puede hacer algo" si no se puede asignar la memoria. Pero la gestión de la memoria es una consideración muy global (!).

La pregunta lo dice todo, pero aquí hay un ejemplo:

typedef struct mutable_t{ int count, max; void **data; } mutable_t; void pushMutable(mutable_t *m, void *object) { if(m->count == m->max){ m->max *= 2; m->data = realloc(m->data, m->max * sizeof(void*)); } // how to handle oom?? m->data[m->count++] = object; }

¿Cómo puedo manejar la falta de memoria y no NULL de todos mis datos?

Editar: supongamos que hay algo que se podría hacer, por ejemplo, liberar algo de memoria en algún lugar o al menos decirle al usuario "no puedes hacer eso, estás fuera de la memoria". Idealmente me gustaría dejar lo que estaba asignado allí.


¡Eso es enteramente tu problema! Aquí hay algunos criterios:

  • Pediste ese recuerdo por una razón. Si no está disponible, ¿el trabajo de tu programa está condenado o puede seguir haciendo cosas? Si es el primero, desea terminar su programa con un mensaje de error; de lo contrario, puede mostrar un mensaje de error de alguna manera y continuar.

  • ¿Existe la posibilidad de intercambiar tiempo por espacio? ¿Podría responder cualquier operación que intentó usar un algoritmo que usa menos memoria? Esto parece mucho trabajo, pero en realidad sería una posibilidad para continuar con el funcionamiento de su programa a pesar de no tener suficiente memoria inicialmente.

  • ¿Estaría mal que su programa continúe cojeando sin estos datos y no haya suficiente memoria? Si es así, debe terminar con un mensaje de error. Es mucho mejor eliminar el programa que continuar el procesamiento ciego de datos incorrectos.


Este es un tema un tanto candente ya que hay esencialmente 2 escuelas de pensamiento sobre el tema

  1. Detecte el OOM y que la función devuelva un código de error.
  2. Detecta la OOM y bloquea tu proceso lo más rápido posible

Personalmente estoy en el campamento # 2. Espere para los tipos de aplicaciones muy especiales, OOM es el período fatal. Es cierto que el código perfectamente escrito puede manejar un OOM, pero muy pocas personas entienden cómo escribir código que sea seguro ante la ausencia de memoria. Incluso menos molestarse en hacerlo porque casi nunca vale la pena el esfuerzo.

No me gusta pasar el código de error a la función de llamada para OOM porque es el equivalente a decirle a la persona que llama "Fallé y no hay nada que puedas hacer al respecto". En su lugar, prefiero estrellarme rápido para que el volcado resultante sea lo más instructivo posible.


He encontrado el problema. La configuración es OS: win7 (64); IDE: vs2013; Debug (Win32).
Cuando mi realloc devolvió el valor nulo debido a la memoria en. Tengo dos soluciones:

1. Cambie la propiedad del proyecto para habilitar DIRECCIONES GRANDES.
2. Cambie la plataforma de mi solución de Win32 a x64.


La estrategia sobre qué hacer cuando falla realloc() depende de su aplicación. La pregunta es demasiado genérica para ser respondida para todos los casos posibles.

Algunas otras notas:

Nunca lo haces:

a = realloc(a, size);

Si falla realloc() , pierde el puntero original y realloc() no free() la memoria original, por lo que tendrá una pérdida de memoria. En su lugar, hacer:

tmp = realloc(a, size); if (tmp) a = tmp; else /* handle error */

El segundo punto que quiero hacer es menor y puede que no sea tan crítico, pero es bueno saberlo de todos modos: aumentar la memoria asignada por un factor f es bueno. Digamos que malloc() n bytes primero. Entonces necesitas más memoria, por lo que realloc() con tamaño n × f . Entonces necesitas más memoria, entonces necesitas n × f 2 bytes. Si desea que realloc() use el espacio de los dos bloques de memoria anteriores, asegúrese de que n × f 2 ≤ n + n × f . Al resolver esta ecuación, obtenemos f≤ (sqrt (5) +1) / 2 = 1.618 (la proporción de oro ). Yo uso un factor de 1.5 mayoría de las veces.


La primera regla que debe seguir cuando trabaje con realloc es no asignar el valor de retorno de realloc al mismo puntero que le pasó. Esta

m->data = realloc(m->data, m->max * sizeof(void*));

es malo. Si realloc falla, devuelve un puntero nulo, pero no desasigna la memoria antigua. El código anterior anulará su m->data mientras que el bloque de memoria antiguo anteriormente señalado por m->data probablemente se convertirá en pérdida de memoria (si no tiene otras referencias).

El valor de retorno de realloc debe almacenarse en un puntero separado primero

void **new_data; ... new_data = realloc(m->data, m->max * sizeof(void*));

Luego puede verificar el éxito / fracaso y cambiar el valor de m->data en caso de éxito

if (new_data != NULL) m->data = new_data; else /* whatever */;


La técnica estándar es introducir una nueva variable para mantener el retorno de realloc. Entonces, solo sobrescribe la variable de entrada si tiene éxito:

tmp = realloc(orig, newsize); if (tmp == NULL) { // could not realloc, but orig still valid } else { orig = tmp; }


También hay otro error sutil que puede venir de realloc. La pérdida de memoria proveniente del puntero NULL devuelto es bastante conocida (pero muy rara de encontrar). En mi programa tuve un bloqueo de vez en cuando que venía de una llamada de realloc. Tenía una estructura dinámica que ajustaba su tamaño automáticamente con un realloc parecido a este:

m->data = realloc(m->data, m->max * sizeof(void*));

El error que cometí fue no verificar m-> max == 0, lo que liberó el área de memoria. Y hecho de mi m-> datos puntero a uno antiguo.

Sé que es un poco fuera de tema, pero este fue el único problema real que tuve con Realloc.