Saltar al contenido

¿Por qué malloc no funciona a veces?

Hola usuario de nuestro sitio web, hemos encontrado la solución a lo que estabas buscando, desplázate y la encontrarás a continuación.

malloc() devuelve un puntero no válido de NULL cuando no puede atender una solicitud de memoria. En la mayoría de los casos, las rutinas de asignación de memoria C administran una lista o un montón de memoria disponible con llamadas al sistema operativo para asignar fragmentos de memoria adicionales cuando un malloc() se realiza la llamada y no hay un bloque en la lista o montón para satisfacer la solicitud.

Entonces el primer caso de malloc() la falla es cuando una solicitud de memoria no puede ser satisfecha porque (1) no hay un bloque de memoria utilizable en la lista o montón del tiempo de ejecución de C y (2) cuando la administración de memoria del tiempo de ejecución de C solicitó más memoria del sistema operativo, el la solicitud fue rechazada.

Aquí hay un artículo sobre las estrategias de asignación de punteros.

Este artículo del foro da un ejemplo de falla de malloc debido a la fragmentación de la memoria.

Otra razón por la que malloc() podría fallar se debe a que las estructuras de datos de administración de memoria se han corrompido probablemente debido a un desbordamiento del búfer en el que un área de memoria que se asignó se usó para un objeto más grande que el tamaño de la memoria asignada. Diferentes versiones de malloc() Puede utilizar diferentes estrategias para la gestión de la memoria y determinar cuánta memoria proporcionar cuando malloc() se llama. Por ejemplo un malloc() puede darle exactamente la cantidad de bytes solicitados o puede darle más de lo que solicitó para ajustar el bloque asignado dentro de los límites de la memoria o para facilitar la administración de la memoria.

Con los sistemas operativos modernos y la memoria virtual, es bastante difícil quedarse sin memoria a menos que esté haciendo un almacenamiento residente de memoria realmente grande. Sin embargo, como mencionó el usuario Yeow_Meng en un comentario a continuación, si está haciendo aritmética para determinar el tamaño a asignar y el resultado es un número negativo, podría terminar solicitando una gran cantidad de memoria porque el argumento para malloc() porque la cantidad de memoria a asignar no está firmada.

Puede encontrarse con el problema de los tamaños negativos al hacer aritmética de punteros para determinar cuánto espacio se necesita para algunos datos. Este tipo de error es común para el análisis de texto que se realiza en texto inesperado. Por ejemplo, el siguiente código daría como resultado un gran malloc() solicitud.

char pathText[64] = "./dir/prefix";  // a buffer of text with path using dot (.) for current dir
char *pFile = strrchr (pathText, '/');  // find last slash where the file name begins
char *pExt = strrchr (pathText, '.');    // looking for file extension 

// at this point the programmer expected that
//   - pFile points to the last slash in the path name
//   - pExt point to the dot (.) in the file extension or NULL
// however with this data we instead have the following pointers because rather than
// an absolute path, it is a relative path
//   - pFile points to the last slash in the path name
//   - pExt point to the first dot (.) in the path name as there is no file extension
// the result is that rather than a non-NULL pExt value being larger than pFile,
// it is instead smaller for this specific data.
char *pNameNoExt;
if (pExt) {  // this really should be if (pExt && pFile < pExt) 
    // extension specified so allocate space just for the name, no extension
    // allocate space for just the file name without the extension
    // since pExt is less than pFile, we get a negative value which then becomes
    // a really huge unsigned value.
    pNameNoExt = malloc ((pExt - pFile + 1) * sizeof(char));
 else 
    pNameNoExt = malloc ((strlen(pFile) + 1) * sizeof(char));

Una buena gestión de la memoria en tiempo de ejecución intentará fusionar los fragmentos de memoria liberados para que muchos bloques más pequeños se combinen en bloques más grandes a medida que se liberan. Esta combinación de fragmentos de memoria reduce las posibilidades de no poder atender una solicitud de memoria utilizando lo que ya está disponible en la lista o el montón de memoria que administra el tiempo de ejecución de administración de memoria C.

Cuanto más pueda reutilizar la memoria ya asignada y menos dependerá de malloc() y free() el mejor. Si no está haciendo un malloc() entonces es difícil que falle.

Cuanto más pueda cambiar muchas llamadas de pequeño tamaño a malloc() a menos llamadas grandes a malloc() menos posibilidades tiene de fragmentar la memoria y ampliar el tamaño de la lista de memoria o del montón con muchos bloques pequeños que no se pueden combinar porque no están uno al lado del otro.

Cuanto más puedas malloc() y free() bloques contiguos al mismo tiempo, es más probable que el tiempo de ejecución de la gestión de memoria pueda fusionar bloques.

No hay ninguna regla que diga que debes hacer un malloc() con el tamaño específico de un objeto, el argumento de tamaño proporcionado a malloc() puede ser mayor que el tamaño necesario para el objeto para el que está asignando memoria. Por lo tanto, es posible que desee utilizar algún tipo de regla para las llamadas a malloc () de modo que los bloques de tamaño estándar se asignen redondeando a una cantidad estándar de memoria. Por lo tanto, puede asignar en bloques de 16 bytes usando una fórmula como ((tamaño / 16) + 1) * 16 o más probable ((tamaño >> 4) + 1) << 4. Muchos lenguajes de escritura usan algo similar para aumentar la posibilidad de llamadas repetidas a malloc() y free() poder hacer coincidir una solicitud con un bloque libre en la lista o montón de memoria.

Aquí hay un ejemplo algo simple de intentar reducir la cantidad de bloques asignados y desasignados. Digamos que tenemos una lista enlazada de bloques de memoria de tamaño variable. Entonces, la estructura de los nodos en la lista vinculada se parece a:

typedef struct __MyNodeStruct 
    struct __MyNodeStruct *pNext;
    unsigned char *pMegaBuffer;
 MyNodeStruct;

Podría haber dos formas de asignar esta memoria para un búfer en particular y su nodo. La primera es una asignación estándar del nodo seguida de una asignación del búfer como se muestra a continuación.

MyNodeStruct *pNewNode = malloc(sizeof(MyNodeStruct));
if (pNewNode)
    pNewNode->pMegaBuffer = malloc(15000);

Sin embargo, otra forma sería hacer algo como lo siguiente, que utiliza una única asignación de memoria con aritmética de puntero para que un solo malloc() proporciona ambas áreas de memoria.

MyNodeStruct *pNewNode = malloc(sizeof(myNodeStruct) + 15000);
if (pNewNode)
    pNewNode->pMegaBuffer = ((unsigned char *)pNewNode) + sizeof(myNodeStruct);

Sin embargo, si está utilizando este método de asignación única, deberá asegurarse de ser coherente en el uso del puntero. pMegaBuffer que no hagas accidentalmente un free() en eso. Y si tiene que cambiar el búfer por un búfer más grande, deberá liberar el nodo y reasignar el búfer y el nodo. Entonces hay más trabajo para el programador.

Otra razón para malloc() fallar en Windows es si su código se asigna en una DLL y se desasigna en una DLL o EXE diferente.

A diferencia de Linux, en Windows una DLL o EXE tiene sus propios enlaces a las bibliotecas en tiempo de ejecución. Eso significa que puede vincular su programa, utilizando el CRT 2013 a una DLL compilada con el CRT 2008.

Los diferentes tiempos de ejecución pueden manejar el montón de manera diferente. Los CRT de depuración y versión definitivamente manejar el montón de manera diferente. Si tu malloc() en depuración y free() en Release, se romperá horriblemente y esto podría estar causando su problema.

Sección de Reseñas y Valoraciones

Nos encantaría que puedieras comunicar este enunciado si si solucionó tu problema.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)


Tags :

Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *