Created
October 20, 2011 00:28
-
-
Save ramntry/1300082 to your computer and use it in GitHub Desktop.
My malloc and free on sbrk()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <unistd.h> | |
#include "malloc.v3.h" | |
// Установка охранника в начало пока пустой кучи | |
// | |
MemoryAllocator::MemoryAllocator() | |
{ | |
oldBrk = sbrk(0); // сохраняем первоначальную позицию границы | |
start = (MemoryBlock*) sbrk(sizeof(MemoryBlock)); // двигаем границу секции .data (статики) на размер охранника | |
start->prev = NULL; // (пока это одновременно и начало кучи - потому prev пуст) | |
start->reserved = 1; // договоримся считать охранник маркером занятой области | |
start->size = 0; // договоримся идентифицировать охранник по нулевому размеру | |
} | |
MemoryAllocator::~MemoryAllocator() | |
{ | |
brk(oldBrk); | |
} | |
// захват памяти в куче | |
// | |
void * MemoryAllocator::malloc(int volume) | |
{ | |
MemoryBlock * curr = start; | |
int to_reserve = (volume + sizeof(int) - 1) / sizeof(int) * // Расчет необходимой памяти: | |
sizeof(int) + sizeof(MemoryBlock); // 1. Выравнивание по разрядности системы (int) | |
// 2. Резервирование места под маркер | |
while (curr->size && // пока не уткнулись в конец кучи (в охранник) | |
(curr->reserved || // и пока маркеры либо занятых областей | |
curr->size < to_reserve)) // либо слишком малых | |
curr = (MemoryBlock*) ((char*)curr + curr->size); // ищем дальше свободное место | |
// нашли свободное место нужного размера или уткнулись в охранник | |
// и разметили место, куда найденный маркер нужно будет передвинуть в связи с | |
// выделением части памяти | |
// | |
MemoryBlock * next = (MemoryBlock*) ((char*)curr + to_reserve); | |
if (curr->size) // если наш curr не охранник - то есть, нашли место в ранее | |
{ // освобожденной области кучи | |
if (curr->size > to_reserve + sizeof(MemoryBlock)) // передвигать маркер, а не просто | |
{ // помечать всю найденную свободную область занятой имеет смысл лишь тогда, | |
// когда остаток места способен вместить нечто большее, чем новый маркер | |
MemoryBlock * nextNext = getNext(curr); // этот маркер нужен, чтобы перенастроить его prev на новый маркер | |
nextNext->prev = next; // перенастраиваем... | |
next->reserved = 0; // помечаем остаток как свободный | |
next->size = curr->size - to_reserve; // размер - как разность размеров | |
curr->size = to_reserve; // а размер выделенного блока - как запрошенный объем с поправками | |
} // на технические потери | |
curr->reserved = 1; // в любом случае помечаем область занятой | |
next->prev = curr; // и настраиваем указатель | |
} | |
else | |
{ // если места не нашли | |
sbrk(to_reserve); // передвигаем программную границу кучи дальше на нужный объем | |
curr->size = to_reserve; | |
next->size = 0; // и настраиваем новый указатель | |
next->reserved = 1; | |
next->prev = curr; | |
} | |
return (void*) (curr + 1); | |
} | |
// освобождение ранее выделенной памяти | |
// | |
void MemoryAllocator::free(void * memory) | |
{ | |
MemoryBlock * toFree = (MemoryBlock*) | |
((char*)memory - sizeof(MemoryBlock)); | |
MemoryBlock * next = getNext(toFree); | |
// этот код должен сдвигать программную границу кучи назад | |
// при освобождении крайних блоков. | |
if (!next->size) // если рядом - край | |
{ // проверить, не нужно ли слить с блоком слева | |
if (toFree->prev && !toFree->prev->reserved) | |
{ // если нужно, то сдвигаем границу на оба блока | |
int t = toFree->prev->size; | |
toFree->prev->size = 0; // и делаем предыдущий маркер охранником | |
toFree->prev->reserved = 1; | |
sbrk(-(toFree->size + t)); | |
} | |
else { // иначе тоже только для крайнего маркера | |
int t = toFree->size; | |
toFree->size = 0; | |
sbrk(-t); | |
} | |
return; | |
} | |
// если с обеих сторон блоки свободные | |
if (toFree->prev && !(next->reserved || toFree->prev->reserved)) | |
{ | |
MemoryBlock * nextNext = getNext(next); | |
toFree->prev->size += toFree->size + next->size; // пометить все как свободное | |
nextNext->prev = toFree->prev; // и верно перенастроить указатель | |
} | |
else if (!next->reserved) | |
{ | |
MemoryBlock * nextNext = getNext(next); | |
toFree->reserved = 0; | |
toFree->size += next->size; | |
nextNext->prev = toFree; | |
} | |
else if (toFree->prev && !toFree->prev->reserved) | |
{ | |
toFree->prev->size += toFree->size; | |
next->prev = toFree->prev; | |
} | |
else | |
toFree->reserved = 0; | |
} | |
void MemoryAllocator::out() | |
{ | |
printf("[%p]: ", oldBrk); | |
int * end = (int*) sbrk(0); | |
int * intOldBrk = (int*) oldBrk; | |
int i = 0; | |
for (; intOldBrk != end; intOldBrk++, i++) | |
printf("%x ", *intOldBrk); | |
printf(" [size: %x]\n", i * sizeof(int) - sizeof(MemoryBlock)); | |
} | |
int * MemoryAllocator::set(int size, int filler) | |
{ | |
int * a = (int*) malloc(sizeof(int) * size); | |
for (int i = 0; i < size; i++) | |
a[i] = filler; | |
return a; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
struct MemoryBlock // маркер блоков памяти в куче - является заголовком каждого блока - | |
{ // и занятого, и свободного, а также терминирующим маркером-охранником | |
MemoryBlock * prev; // указатель на предыдущий такой маркер | |
unsigned int reserved; // характер блока - свободный или занятый | |
unsigned int size; // размер структурированной области данных - размер размеченного | |
}; // участка вместе с последующим маркером - очередным или охранником | |
class MemoryAllocator | |
{ | |
public: | |
MemoryAllocator(); | |
~MemoryAllocator(); | |
void * malloc(int volume); | |
void free(void * memory); | |
void out(); | |
int * set(int size, int filler); | |
private: | |
MemoryBlock * start; | |
void * oldBrk; | |
inline MemoryBlock * getNext (MemoryBlock * block) | |
{ return (MemoryBlock*) ((char*)block + block->size); } | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include "malloc.v3.h" | |
using namespace std; | |
int main() | |
{ | |
MemoryAllocator ma; | |
ma.out(); | |
int * a = ma.set(8, 2); // создать memory_malloc'ом массив int[8] и забить его 2 | |
ma.out(); | |
int * b = ma.set(6, 3); | |
ma.out(); | |
ma.free(a); | |
ma.out(); | |
a = ma.set(4, 4); | |
ma.out(); | |
int * c = ma.set(1, 9); // воткнем девяточку в единственное свободное окошко | |
ma.out(); | |
ma.free(b); | |
ma.out(); | |
ma.free(a); | |
ma.out(); | |
ma.free(c); // полное слияние свободных областей | |
ma.out(); // память свободна | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /bin/sh | |
g++ simple_test.cpp malloc.v3.cpp -o simple_test | |
cat simple_test.cpp | |
./simple_test | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment