* Reimplemented realloc() to reuse the previous buffer if possible and useful.
* Cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34409 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2007, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Copyright 2003-2009, Axel Dörfler, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -23,20 +23,20 @@
|
||||
#endif
|
||||
|
||||
|
||||
/* This is a very simple malloc()/free() implementation - it only
|
||||
* manages a free list.
|
||||
* After heap_init() is called, all free memory is contained in one
|
||||
* big chunk, the only entry in the free link list (which is a single
|
||||
* linked list).
|
||||
* When memory is allocated, the smallest free chunk that contains
|
||||
* the requested size is split (or taken as a whole if it can't be
|
||||
* splitted anymore), and it's lower half will be removed from the
|
||||
* free list.
|
||||
* The free list is ordered by size, starting with the smallest
|
||||
* free chunk available. When a chunk is freed, it will be joint
|
||||
* with its predecessor or successor, if possible.
|
||||
* To ease list handling, the list anchor itself is a free chunk with
|
||||
* size 0 that can't be allocated.
|
||||
/*! This is a very simple malloc()/free() implementation - it only
|
||||
manages a free list.
|
||||
After heap_init() is called, all free memory is contained in one
|
||||
big chunk, the only entry in the free link list (which is a single
|
||||
linked list).
|
||||
When memory is allocated, the smallest free chunk that contains
|
||||
the requested size is split (or taken as a whole if it can't be
|
||||
splitted anymore), and it's lower half will be removed from the
|
||||
free list.
|
||||
The free list is ordered by size, starting with the smallest
|
||||
free chunk available. When a chunk is freed, it will be joint
|
||||
with its predecessor or successor, if possible.
|
||||
To ease list handling, the list anchor itself is a free chunk with
|
||||
size 0 that can't be allocated.
|
||||
*/
|
||||
|
||||
#define DEBUG_ALLOCATIONS
|
||||
@@ -58,6 +58,9 @@ struct free_chunk {
|
||||
};
|
||||
|
||||
|
||||
const static uint32 kAlignment = 4;
|
||||
// all memory chunks will be a multiple of this
|
||||
|
||||
static void* sHeapBase;
|
||||
static uint32 /*sHeapSize,*/ sMaxHeapSize, sAvailable;
|
||||
static free_chunk sFreeAnchor;
|
||||
@@ -149,7 +152,8 @@ free_chunk::Remove(free_chunk *previous)
|
||||
void
|
||||
free_chunk::Enqueue()
|
||||
{
|
||||
free_chunk *chunk = sFreeAnchor.next, *last = &sFreeAnchor;
|
||||
free_chunk* chunk = sFreeAnchor.next;
|
||||
free_chunk* last = &sFreeAnchor;
|
||||
while (chunk && chunk->Size() < size) {
|
||||
last = chunk;
|
||||
chunk = chunk->next;
|
||||
@@ -191,7 +195,8 @@ heap_release(stage2_args *args)
|
||||
status_t
|
||||
heap_init(stage2_args* args)
|
||||
{
|
||||
void *base, *top;
|
||||
void* base;
|
||||
void* top;
|
||||
if (platform_init_heap(args, &base, &top) < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
@@ -234,11 +239,13 @@ grow_heap(uint32 bytes)
|
||||
void
|
||||
dump_chunks(void)
|
||||
{
|
||||
free_chunk *chunk = sFreeAnchor.next, *last = &sFreeAnchor;
|
||||
free_chunk* chunk = sFreeAnchor.next;
|
||||
free_chunk* last = &sFreeAnchor;
|
||||
while (chunk != NULL) {
|
||||
last = chunk;
|
||||
|
||||
printf("\t%p: chunk size = %ld, end = %p, next = %p\n", chunk, chunk->size, (uint8 *)chunk + chunk->size, chunk->next);
|
||||
printf("\t%p: chunk size = %ld, end = %p, next = %p\n", chunk,
|
||||
chunk->size, (uint8*)chunk + chunk->size, chunk->next);
|
||||
chunk = chunk->next;
|
||||
}
|
||||
}
|
||||
@@ -257,15 +264,16 @@ malloc(size_t size)
|
||||
if (sHeapBase == NULL || size == 0)
|
||||
return NULL;
|
||||
|
||||
// align the size requirement to a 4 bytes boundary
|
||||
size = (size + 3) & 0xfffffffc;
|
||||
// align the size requirement to a kAlignment bytes boundary
|
||||
size = (size - 1 + kAlignment) & ~(size_t)(kAlignment - 1);
|
||||
|
||||
if (size > sAvailable) {
|
||||
dprintf("malloc(): Out of memory!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free_chunk *chunk = sFreeAnchor.next, *last = &sFreeAnchor;
|
||||
free_chunk* chunk = sFreeAnchor.next;
|
||||
free_chunk* last = &sFreeAnchor;
|
||||
while (chunk && chunk->Size() < size) {
|
||||
last = chunk;
|
||||
chunk = chunk->next;
|
||||
@@ -277,10 +285,10 @@ malloc(size_t size)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (chunk->Size() > size + sizeof(free_chunk) + 4) {
|
||||
if (chunk->Size() > size + sizeof(free_chunk) + kAlignment) {
|
||||
// if this chunk is bigger than the requested size,
|
||||
// we split it to form two chunks (with a minimal
|
||||
// size of 4 allocatable bytes).
|
||||
// size of kAlignment allocatable bytes).
|
||||
|
||||
free_chunk* freeChunk = chunk->Split(size);
|
||||
last->next = freeChunk;
|
||||
@@ -304,25 +312,34 @@ malloc(size_t size)
|
||||
void*
|
||||
realloc(void* oldBuffer, size_t newSize)
|
||||
{
|
||||
// ToDo: improve this implementation!
|
||||
|
||||
if (newSize == 0) {
|
||||
TRACE("realloc(%p, %lu) -> NULL\n", oldBuffer, newSize);
|
||||
free(oldBuffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t copySize = newSize;
|
||||
if (oldBuffer != NULL) {
|
||||
free_chunk* oldChunk = free_chunk::SetToAllocated(oldBuffer);
|
||||
|
||||
// Check if the old buffer still fits, and if it makes sense to keep it
|
||||
if (oldChunk->size >= newSize
|
||||
&& (oldChunk->size < 128 || newSize > oldChunk->size / 3)) {
|
||||
TRACE("realloc(%p, %lu) old buffer is large enough\n",
|
||||
oldBuffer, newSize);
|
||||
return oldChunk->AllocatedAddress();
|
||||
}
|
||||
|
||||
if (copySize > oldChunk->size)
|
||||
copySize = oldChunk->size;
|
||||
}
|
||||
|
||||
void* newBuffer = malloc(newSize);
|
||||
if (newBuffer == NULL)
|
||||
return NULL;
|
||||
|
||||
if (oldBuffer) {
|
||||
free_chunk *oldChunk = free_chunk::SetToAllocated(oldBuffer);
|
||||
|
||||
if (newSize > oldChunk->size)
|
||||
newSize = oldChunk->size;
|
||||
|
||||
memcpy(newBuffer, oldBuffer, newSize);
|
||||
if (oldBuffer != NULL) {
|
||||
memcpy(newBuffer, oldBuffer, copySize);
|
||||
free(oldBuffer);
|
||||
}
|
||||
|
||||
@@ -359,7 +376,8 @@ free(void *allocated)
|
||||
// try to join the new free chunk with an existing one
|
||||
// it may be joined with up to two chunks
|
||||
|
||||
free_chunk *chunk = sFreeAnchor.next, *last = &sFreeAnchor;
|
||||
free_chunk* chunk = sFreeAnchor.next;
|
||||
free_chunk* last = &sFreeAnchor;
|
||||
int32 joinCount = 0;
|
||||
|
||||
while (chunk) {
|
||||
|
||||
Reference in New Issue
Block a user