2009-10-31 21 views
5

la siguiente es una versión muy simple de malloc() y parece asignarme algo de espacio, pero aparte del hecho de que no hay libre() y no compruebo si he invadido el espacio asignado, ¿cómo puedo verificar que el código sea correcto?Asignación de memoria en C

¿Alguna obvia equivocación que los expertos de "C" me abofetearían?

#include <stdio.h> 
#include <unistd.h> 

#define MAX_MEMORY 1024 * 1024 * 2 /* 2MB of memory */ 

void *stack = NULL; /* pointer to available stack */ 
void * memoryAlloc(size) { 
    if (stack == NULL) 
     stack = sbrk(MAX_MEMORY); /* give us system memory */ 

    void *pointer; 
    pointer = (void *)stack + size; /* we always have space :) */ 
    stack += size; /* move in stack forward as space allocated */ 
    return pointer; 
} 
+0

No llamaría a la arena de la memoria "pila". Su implementación actual es como una pila, sí, pero si tiene la intención de que funcione como lo hace malloc, con free, entonces es un montón. –

+0

Muchas gracias chicos por todos sus comentarios! – Radek

+0

Este asignador es el comienzo de algo llamado 'asignador de grupo' - las asignaciones ocurren como las anteriores, luego todo el bloque se libera de vuelta al sistema de una vez cuando se completa la unidad de trabajo que utiliza el grupo. Ayuda a lidiar con fugas causadas por tener que administrar cada pequeña asignación por separado. Apache utiliza pools: entra una solicitud HTTP, se configura un pool para la solicitud, cuando se completa la solicitud, se libera el pool. Nada más que trabaje en la solicitud debe preocuparse por liberar objetos asignados dinámicamente. –

Respuesta

11

Además de los problemas básicos Ned Batchelder señaló, un problema mucho más sutil es que un asignador tiene que devolver una dirección que está correctamente alineado para cualquier objeto que está siendo asignado. En algunas plataformas (x86) esto puede no importar, excepto por problemas de rendimiento, pero en muchas plataformas es un factor decisivo.

También tuve que realizar un molde (char*) para realizar la aritmética del puntero stack (no se puede hacer la aritmética del puntero en los tipos void*).

Y debe poner parens alrededor de la expresión en la macro MAX_MEMORY. No creo que haya ningún problema de precedencia en el que te metas sin ellos, ya que todos los operadores de alta precedencia que la multiplicación no serían la sintaxis correcta de todos modos. Con macros, es siempre mejor que lo siento. (Hay al menos una excepción en la que el operador [] podría vincular solo a la expresión 2 y no a toda MAX_MEMORY, pero sería una situación muy extraña ver MAX_MEMORY[arrayname], incluso si es sintácticamente válida).

De hecho, lo hubiera convertido en una enumeración.

probablemente Puede mantener el asignador sencilla mediante la devolución de un bloque de memoria que está correctamente alineado para cualquier tipo de datos básicos sobre el sistema (tal vez una alineación de 8 bytes):

/* Note: the following is untested     */ 
/*  it includes changes suggested by Batchelder */ 

#include <stdio.h> 
#include <unistd.h> 

enum { 
    kMaxMemory = 1024 * 1024 * 2, /* 2MB of memory */ 
    kAlignment = 8 
}; 

void *stack = NULL; /* pointer to available stack */ 
void * memoryAlloc(size_t size) { 
    void *pointer; 

    size = (size + kAlignment - 1) & ~(kAlignment - 1); /* round size up so allocations stay aligned */ 

    if (stack == NULL) 
    stack = sbrk(kMaxMemory); /* give us system memory */ 

    pointer = stack; /* we always have space :) */ 
    stack = (char*) stack + size; /* move in stack forward as space allocated */ 
    return pointer; 
} 
+0

Probado y funcionando – Radek

6

Hay algunos problemas:

  1. se declara pointer en medio de la función, que no está permitido en C.

  2. Se establece puntero a stack+size, pero quieres que sea solo stack. De lo contrario, está devolviendo un puntero al final del bloque de memoria que está asignando. Como resultado, si su interlocutor usa todos los size bytes en ese puntero, se solapará con otro bloque de memoria. Si obtiene bloques de diferentes tamaños en diferentes momentos, tendrá dos personas que llaman tratando de usar los mismos bytes de memoria.

  3. Al hacer stack += size, que está incrementando stack no por size bytes sino por size void * 's, que es casi siempre mayor.

+3

Se han permitido declaraciones en el medio de una función desde C99. –

+0

oops: ¡Estoy mostrando mi edad! –

+0

todos los puntos buenos, +1 –

2

En primer lugar, como otros ya han señalado , está declarando variables en el medio del bloque, que solo está permitido en C99, pero no en C89/90. Es decir. tenemos que concluir que estás usando C99.

En segundo lugar, está definiendo su función en K & estilo R (sin tipo de parámetro), pero al mismo tiempo no declara el tipo de parámetro más tarde. De esta forma, usted confía en la regla "implícita int", que está prohibida en C99. Es decir.tenemos que concluir que eres no usando C99. Esto ya es una contradicción con la parte "primero". (Además, es costumbre usar unsigned tipos para representar el concepto de "tamaño de objeto". size_t es un tipo dedicado normalmente utilizado para ese fin).

En tercer lugar, está utilizando la aritmética del puntero en un puntero void *, que siempre es ilegal en C89/90 y C99. Ni siquiera sé qué podemos concluir de eso :)

Por favor, decida qué idioma está tratando de usar, y iremos desde allí.

+0

Me perdí la declaración implícita de 'size'. –

+0

Gracias AndreyT, voy a usar C89 y puedes concluir que soy un novato pero con mucha información útil ahora :). – Radek

Cuestiones relacionadas