Skip to content

Commit ce42efe

Browse files
authored
Implement advanced malloc features (#31)
## Description Implement advanced malloc features. ## Issues <!-- use if this PR fully resolves the issue --> Closes #29 <!-- use if this PR is linked but should not close the issue --> Related: #<issue-number> ## Testing <!-- Steps or notes on how reviewers can verify. -->
1 parent 72a6145 commit ce42efe

File tree

2 files changed

+121
-26
lines changed

2 files changed

+121
-26
lines changed

include/malloc_from_scratch/memory_internal.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,22 @@ inline size_t total_memory_allocated = 0;
2222
inline pthread_mutex_t allocator_mutex = PTHREAD_MUTEX_INITIALIZER;
2323

2424
constexpr size_t BLOCK_METADATA_SIZE = sizeof(MemoryBlock);
25-
constexpr size_t MIN_BLOCK_SIZE = 16;
25+
constexpr size_t BLOCK_SIZE = 16;
26+
constexpr size_t CHUNK_SIZE = 65536;
2627

28+
// malloc
29+
void* increaseHeap(size_t size);
30+
MemoryBlock* findLargeEnoughFreeMemoryBlock(MemoryBlock** block_list_head, size_t size);
31+
void* splitFreeMemoryBlockIfPossible(MemoryBlock* new_block, size_t size);
32+
void* getMemoryBlockSplitAddress(MemoryBlock* new_block, size_t size);
2733
void insertMemoryBlockAtEnd(MemoryBlock** block_list_head, MemoryBlock* new_block);
34+
35+
// helpers
2836
void* getPayloadAddress(MemoryBlock* block);
2937
MemoryBlock* getMetadata(void* payload_address);
30-
void* increaseHeap(size_t size);
31-
void* decreaseHeap(MemoryBlock* block_heap_end, size_t size);
38+
MemoryBlock* getMemoryBlockFromAddress(void* address);
39+
size_t getSizeOfAllocatedMemoryBlock(MemoryBlock* block);
40+
void* getErrorCodeInVoidPtr(size_t error_code);
3241

3342
} // namespace internal
3443
} // namespace mem

src/malloc.cpp

Lines changed: 109 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "malloc_from_scratch/memory_allocator.h"
22
#include "malloc_from_scratch/memory_internal.h"
33

4+
#include <cstdlib>
45
#include <unistd.h>
56

67
namespace mem
@@ -15,28 +16,117 @@ void* malloc(size_t size)
1516

1617
internal::total_memory_allocated += size;
1718

18-
size_t total_size = sizeof(internal::MemoryBlock) + size;
19+
internal::MemoryBlock* found_block =
20+
internal::findLargeEnoughFreeMemoryBlock(&internal::block_list_head, size);
1921

20-
void* new_memory_allocation = internal::increaseHeap(total_size);
21-
if (new_memory_allocation == NULL)
22+
if (found_block != nullptr)
23+
{
24+
void* return_address = internal::splitFreeMemoryBlockIfPossible(found_block, size);
25+
return return_address;
26+
}
27+
28+
bool is_frame_used = false;
29+
size_t total_size = 0;
30+
if (size < internal::CHUNK_SIZE)
2231
{
23-
return NULL;
32+
total_size = internal::BLOCK_METADATA_SIZE + internal::CHUNK_SIZE;
33+
is_frame_used = true;
34+
}
35+
else
36+
{
37+
total_size = internal::BLOCK_METADATA_SIZE + size;
38+
is_frame_used = false;
2439
}
2540

26-
internal::MemoryBlock* new_block =
27-
reinterpret_cast<internal::MemoryBlock*>(new_memory_allocation);
28-
new_block->size_ = size;
29-
new_block->allocated_ = 1;
30-
new_block->next_ = nullptr;
41+
void* new_memory_allocation = internal::increaseHeap(total_size);
42+
if (new_memory_allocation == nullptr)
43+
{
44+
return nullptr;
45+
}
3146

32-
internal::insertMemoryBlockAtEnd(&internal::block_list_head, new_block);
47+
internal::MemoryBlock* new_block = internal::getMemoryBlockFromAddress(new_memory_allocation);
48+
if (is_frame_used)
49+
{
50+
new_block->size_ = internal::CHUNK_SIZE;
51+
new_block->allocated_ = false;
52+
new_block->next_ = nullptr;
53+
internal::insertMemoryBlockAtEnd(&internal::block_list_head, new_block);
54+
void* return_address = internal::splitFreeMemoryBlockIfPossible(new_block, size);
55+
return return_address;
56+
}
57+
else
58+
{
59+
new_block->size_ = size;
60+
new_block->allocated_ = true;
61+
new_block->next_ = nullptr;
62+
internal::insertMemoryBlockAtEnd(&internal::block_list_head, new_block);
63+
}
3364

3465
return internal::getPayloadAddress(new_block);
3566
}
3667

3768
namespace internal
3869
{
3970

71+
void* increaseHeap(size_t size)
72+
{
73+
void* result = sbrk(static_cast<intptr_t>(size));
74+
if (result == getErrorCodeInVoidPtr(-1) || result == getErrorCodeInVoidPtr(0))
75+
{
76+
exit(-1);
77+
}
78+
79+
return result;
80+
}
81+
82+
MemoryBlock* findLargeEnoughFreeMemoryBlock(MemoryBlock** block_list_head, size_t size)
83+
{
84+
MemoryBlock* current = *block_list_head;
85+
while (current != nullptr)
86+
{
87+
if (current->allocated_ == false && current->size_ >= size)
88+
{
89+
return current;
90+
}
91+
current = current->next_;
92+
}
93+
return nullptr;
94+
}
95+
96+
void* splitFreeMemoryBlockIfPossible(MemoryBlock* new_block, size_t size)
97+
{
98+
if (new_block == nullptr)
99+
{
100+
return nullptr;
101+
}
102+
103+
size_t remaining_size = new_block->size_ - size;
104+
char one_byte_payload_size_requirement = 1;
105+
if (remaining_size >= BLOCK_METADATA_SIZE + one_byte_payload_size_requirement)
106+
{
107+
void* split_address = getMemoryBlockSplitAddress(new_block, size);
108+
MemoryBlock* new_temp_block = getMemoryBlockFromAddress(split_address);
109+
new_temp_block->size_ = remaining_size - BLOCK_METADATA_SIZE;
110+
new_temp_block->allocated_ = false;
111+
new_temp_block->next_ = new_block->next_;
112+
113+
new_block->size_ = size;
114+
new_block->allocated_ = true;
115+
new_block->next_ = new_temp_block;
116+
}
117+
else
118+
{
119+
new_block->allocated_ = true;
120+
}
121+
122+
return getPayloadAddress(new_block);
123+
}
124+
125+
void* getMemoryBlockSplitAddress(MemoryBlock* new_block, size_t size)
126+
{
127+
return (reinterpret_cast<char*>(getPayloadAddress(new_block)) + size);
128+
}
129+
40130
void insertMemoryBlockAtEnd(MemoryBlock** block_list_head, MemoryBlock* new_block)
41131
{
42132
if (*block_list_head == nullptr)
@@ -54,6 +144,7 @@ void insertMemoryBlockAtEnd(MemoryBlock** block_list_head, MemoryBlock* new_bloc
54144
}
55145
}
56146

147+
// helpers
57148
void* getPayloadAddress(MemoryBlock* block)
58149
{
59150
if (!block)
@@ -66,26 +157,21 @@ void* getPayloadAddress(MemoryBlock* block)
66157

67158
MemoryBlock* getMetadata(void* payload_address)
68159
{
69-
if (!payload_address)
70-
{
71-
return nullptr;
72-
}
73-
74160
return reinterpret_cast<MemoryBlock*>(reinterpret_cast<char*>(payload_address) -
75161
BLOCK_METADATA_SIZE);
76162
}
77163

78-
void* increaseHeap(size_t size)
164+
MemoryBlock* getMemoryBlockFromAddress(void* address)
79165
{
80-
void* result = sbrk(static_cast<intptr_t>(size));
81-
if (result == reinterpret_cast<void*>(-1))
82-
{
83-
return nullptr;
84-
}
166+
return reinterpret_cast<MemoryBlock*>(address);
167+
}
85168

86-
return result;
169+
size_t getSizeOfAllocatedMemoryBlock(MemoryBlock* block)
170+
{
171+
return reinterpret_cast<size_t>(getPayloadAddress(block));
87172
}
88173

89-
void* decreaseHeap(MemoryBlock* block_heap_end, size_t size) { return nullptr; }
174+
void* getErrorCodeInVoidPtr(size_t error_code) { return reinterpret_cast<void*>(error_code); }
175+
90176
} // namespace internal
91177
} // namespace mem

0 commit comments

Comments
 (0)