Oprócz podstawowych problemów Ned Batchelder wskazał, znacznie bardziej subtelny problemem jest to, że podzielnik ma powrócić adres, który jest właściwie wyrównany dla cokolwiek obiekt jest przydzielona. Na niektórych platformach (x86) może to nie mieć znaczenia, z wyjątkiem problemów związanych z wydajnością, ale na wielu platformach jest to kompletne rozwiązanie.
Musiałem również wykonać rzutowanie (char*)
, aby wykonać arytmetykę wskaźnika stack
(nie można wykonywać arytmetyki wskaźników na typach void*
).
Powinieneś umieścić parens wokół wyrażenia w makrze MAX_MEMORY
. Nie sądzę, by istniały jakiekolwiek problemy pierwszeństwa, w które się wchodzisz bez nich, ponieważ wszyscy operatorzy o wysokim priorytecie niż mnożenie nie mieliby poprawnej składni. W przypadku makr jest to zawsze bezpieczniejsze niż przykro mi. (Istnieje co najmniej jeden wyjątek, w którym operator []
może wiązać tylko z wyrażeniem 2
, a nie całe wyrażenie MAX_MEMORY
, ale byłoby to bardzo dziwne, aby zobaczyć MAX_MEMORY[arrayname]
, nawet jeśli jest poprawny pod względem składni).
W gruncie rzeczy zrobiłabym to wyliczeniem.
Prawdopodobnie można zachować podzielnika prosty wracając blok pamięci, który jest właściwie wyrównany dla dowolnego podstawowego typu danych w systemie (może przyrównanie 8 bajtów):
/* 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;
}
Nie nazwałbym areny pamięci "stosem". Twoja obecna implementacja jest jak stos, tak, ale jeśli zamierzasz działać tak jak malloc, za darmo, to jest kupa. –
Dziękuję wszystkim za wszystkie komentarze! – Radek
Ten podzielnik jest początkiem czegoś, co nazywa się "przydziałem puli" - alokacje odbywają się tak, jak powyżej, a następnie cały blok jest natychmiast zwracany do systemu, gdy jednostka pracy korzystająca z puli zostanie ukończona. Pomaga w radzeniu sobie z wyciekami spowodowanymi koniecznością zarządzania każdą małą alokacją osobno. Apache wykorzystuje pule - przychodzi żądanie HTTP, pula jest skonfigurowana dla żądania, po zakończeniu żądania pula jest zwalniana. Nic, co zajmuje się tą sprawą, nie musi martwić się o zwalnianie dynamicznie przydzielanych obiektów. –