2009-10-31 8 views
5

ce qui suit est une version très très simple de malloc() et semble allouer un peu d'espace pour moi, mais en dehors du fait qu'il n'y a pas free() et je ne vérifie pas si je J'ai dépassé l'espace alloué, comment puis-je vérifier que le code est correct?allocation de mémoire en C

Y a-t-il des bévues évidentes pour lesquelles les experts en «C» me gifleraient?

#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

Je n'appellerais pas l'arène de la mémoire "pile". Votre implémentation actuelle est comme une pile, oui, mais si vous voulez que cela fonctionne comme malloc, avec free, alors c'est un tas. –

+0

Merci beaucoup les gars pour tous vos commentaires! – Radek

+0

Cet allocateur est le début de ce que l'on appelle un 'allocateur de pool' - les allocations se produisent comme ci-dessus, puis le bloc entier est immédiatement libéré dans le système lorsque l'unité de travail utilisant le pool est terminée. Il aide à gérer les fuites causées par la gestion séparée de chaque petite allocation. Apache utilise des pools - une requête HTTP arrive, un pool est configuré pour la requête, une fois la requête terminée, le pool est libéré. Rien d'autre travaillant sur la requête ne doit s'inquiéter de libérer des objets alloués dynamiquement. –

Répondre

11

En plus des problèmes de base Ned Batchelder a souligné, un problème beaucoup plus subtile est qu'un allocateur doit retourner une adresse qui est correctement aligné pour tout objet est alloué. Sur certaines plates-formes (x86), cela peut ne pas avoir d'importance, sauf pour les problèmes de performances, mais sur de nombreuses plates-formes, c'est un briseur d'accord complet.

J'ai également dû effectuer un cast (char*) pour effectuer l'arithmétique de pointeur stack (vous ne pouvez pas faire d'arithmétique de pointeur sur les types void*).

Et vous devriez mettre parens autour de l'expression dans la macro MAX_MEMORY. Je ne pense pas qu'il y ait des problèmes de préséance que vous auriez sans eux, car tous les opérateurs de haute priorité que la multiplication ne serait pas de toute façon une syntaxe correcte. Avec les macros, c'est toujours mieux mieux vaut prévenir que guérir. (Il existe au moins une exception où l'opérateur [] peut se lier uniquement au 2 et non pas à l'expression entière MAX_MEMORY, mais ce serait une situation très étrange de voir MAX_MEMORY[arrayname], même si elle est syntaxiquement valide).

En fait, j'en aurais fait une énumération.

Vous pouvez probablement garder le allocateur simple, en retournant un bloc de mémoire qui est correctement aligné pour tout type de données de base sur le système (peut-être un alignement de 8 octets):

/* 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

Testé et fonctionnant – Radek

6

Il y a quelques problèmes:

  1. Vous déclarez pointer au milieu de la fonction, ce qui est interdit dans C.

  2. Vous définissez pointeur sur stack+size, mais vous voulez qu'il soit juste stack. Sinon, vous renvoyez un pointeur vers la fin du bloc de mémoire que vous allouez. Par conséquent, si votre appelant utilise tous les size octets à ce pointeur, il va se chevaucher avec un autre bloc de mémoire. Si vous obtenez des blocs de tailles différentes à des moments différents, deux appelants essaieront d'utiliser les mêmes octets de mémoire.

  3. Lorsque vous faites stack += size, vous incrémenter stack non par size octets mais par size void * 's, ce qui est presque toujours plus grande.

+3

Les déclarations au milieu d'une fonction ont été autorisées depuis C99. –

+0

oups: Je montre mon âge! –

+0

tous les bons points, +1 –

2

Tout d'abord, comme d'autres l'ont déjà noté , vous déclarez des variables au milieu du bloc, ce qui n'est autorisé qu'en C99, mais pas en C89/90. C'est à dire. nous devons conclure que vous utilisez C99.

Deuxièmement, vous définissez votre fonction dans K & R-style (pas de type de paramètre), mais en même temps ne pas déclarer le type de paramètre plus tard. De cette façon, vous vous appuyez sur la règle "implicit int", qui est interdite en C99. C'est à dire.nous devons conclure que vous êtes pas en utilisant C99. C'est déjà une contradiction avec la partie "premièrement". (De plus, il est habituel d'utiliser types non signés pour représenter le concept de "taille d'objet" size_t est un type dédié normalement utilisé à cette fin).

Troisièmement, vous utilisez l'arithmétique de pointeur sur un pointeur void *, ce qui est toujours illégal dans C89/90 et C99. Je ne sais même pas ce que nous pouvons en conclure :)

S'il vous plaît, décidez quelle langue vous essayez d'utiliser, et nous irons à partir de là.

+0

J'ai manqué la déclaration implicite de 'size'. –

+0

Merci AndreyT, je vais utiliser C89 et vous pouvez conclure que je suis un débutant mais avec beaucoup de commentaires utiles maintenant :). – Radek