git clone https://github.com/Epicurius/Dynamic-memory-library.git libdm
cd libdm
makeFor each allocation the library saves some metadata in 'struct block'.
struct block
{
struct block *next;
int free;
char str[4];
size_t size;
};| Variable | Explanation | Bytes |
|---|---|---|
| struct block *next | Pointer to the next block, NULL if is the last one. | 8 |
| int free | Bool for whether the block is free or reserved. | 4 |
| char str[4] | Utilized by 'ft_malloc()' to save hash. | 1 * 4 |
| size_t size | Size of the memory stored. | 8 |
So every time an allocation is requested the total occupied memory is requested size + sizeof(struct block).
Each block is contained in a zone, zones are a large block of memory that act like a buffer from which we can distribute smaller chunks of memory on request.
For example, 100 'malloc(5)' calls will request memory 100 times from the operating system, which is very slow. Instead we request a larger chunk of memory at once and divvy it up ourselves, 'struct zone' is used to store the zones memory's boundaries.
struct zone
{
struct zone *next;
void *end;
};| Variable | Explanation | Bytes |
|---|---|---|
| struct s_zone *next | Pointer to the next zone, NULL if is the last one. | 8 |
| void *end | Pointer to the the end of the zone. | 8 |
There are 3 zone types; TINY, SMALL and LARGE.
TINY/SMALL zone size is the lowest possible amount of PAGE_SIZE that can fit the minimum amount of blocks:
(sizeof(struct block) + avg. block size) * BLOCKS_PER_ZONE + sizeof(struct zone).
LARGE zone is the exception, it will always contain one block and will request memory on demand:
requested size + sizeof(struct block) + sizeof(struct zone).
There are some macros in 'include/libdm.h' that the user can modify:
| Macro | Explanation |
|---|---|
| MEM_TINY_MAX | maximum size of a TINY block. (min. is 0) |
| MEM_SMALL_MAX | maximum size of a SMALL block. (min. is MEM_TINY_MAX) |
| BLOCKS_PER_ZONE | minimum amount of average blocks that a zone should contain |
| PAGE_SIZE | the page size, by default 'getpagesize()' is used to figure it out |
TINY/SMALL example:
'malloc(5)' is called 100 times, the first call will allocate a TINY zone, but only use 5 + sizeof(struct block) + sizeof(struct zone) bytes.
For the next 99 times it does not need to request memory, because it can utilize the remaining space left in TINY zone.
And each subsequent 'malloc()' call will only use 5 + sizeof(struct block).
When a zone is filled up the next 'malloc()' call will create a new zone and repeat the process.
LARGE example:
When 'malloc(100000)' is called, a LARGE zone is allocated 100000 + sizeof(struct block) + sizeof(struct zone).
Any subsequent LARGE allocations will repeat the process.
When a TINY or SMALL block is freed it not erased or freed, instead the block is marked as unused. Additionally if the previous or following block is free the blocks will merged into 1 free block, essentially a type of “Defragmentation”. The zone is freed if it has no reserved blocks and there are multiple zones of the same type.
When a LARGE block is freed the entire zone is deallocated, even if there is only 1 LARGE zone.
- Library is “Thread safe”, it is safe to use is multithreaded projects.
- 'ft_memshow(int fd, int flags)' is useful debugging tool. See 'Personal help functions' section for more info.
- 'ft_malloc(size_t *size, char *hash)' same as standard malloc but takes in a 4 char hash and saves it in struct block->str. The 4 bytes where going to waste so I use them with ft_malloc() to mark individual memory blocks. The hash can be viewed with 'ft_memshow(1, MEM_SHOW_HASH)'.
- 'ft_memfind(char *hash)' returns a pointer to the memory with same hash. Note: Use ft_malloc().
- 'ft_mempurge(void)' frees all the memory allocated by 'malloc()', 'realloc()', 'calloc()', 'ft_malloc()'. Without the developer having to free every individual memory block themselves.
void *malloc(size_t size)
- Allocates size_t size amount of memory.
void *calloc(size_t num, size_t size)
- Allocates size_t size amount of memory ans sets num amount to null.
void *realloc(void *ptr, size_t size)
- Changes the memory pointed by ptr to size without loosing what it saved in it.
void free(void *ptr)
- Frees the memory pointed to by *ptr.
void *ft_malloc(size_t size, char *code)
- Allocates size_t size amount of memory and saves code for debugging.
void *ft_memfind(char *hash)
- Find pointer to memory with hash.
void ft_mempurge(void)
- Deletes all memory that was allocated.
void ft_memshow(int fd, int flags)
- Print useful info to 'fd'.
-----------------------------------------------------------------------
MEM_SHOW_TINY = Print all TINY memory allocations.
MEM_SHOW_SMALL = Print all SMALL memory allocations.
MEM_SHOW_LARGE = Print all LARGE memory allocations.
MEM_SHOW_HEX = Print each allocated byte in hexadecimal.
MEM_SHOW_CHAR = Print each allocated byte in hex and char. (overrides 'MEM_SHOW_HEX')
MEM_SHOW_FREE = Print all memory slots that are free.
MEM_SHOW_HASH = Print all hash. (Use ft_malloc)
-----------------------------------------------------------------------
#inlude "libdm.h"
void main(void)
{
char *str[5];
str[0] = malloc(10);
str[1] = malloc(400);
str[2] = realloc(str[2], 20);
str[3] = ft_malloc(5, "STR");
str[4] = malloc(2048);
free(str[4]);
str[4] = malloc(4096);
ft_memshow(1, MEM_SHOW_HASH | MEM_SHOW_FREE);
ft_mempurge();
}#inlude <stdio.h>
#inlude <string.h>
#inlude "libdm.h"
void main(void)
{
char *str;
str = ft_malloc(sizeof(char) * 12, "TEST");
strcpy(str, "Hello World");
ft_memshow(1, MEM_SHOW_TINY | MEM_SHOW_HASH | MEM_SHOW_CHAR);
ft_mempurge();
}

