diff --git a/Src/Hallocy/Allocator.c b/Src/Hallocy/Allocator.c index 79151e5..ba86aa7 100644 --- a/Src/Hallocy/Allocator.c +++ b/Src/Hallocy/Allocator.c @@ -24,6 +24,8 @@ #if defined(_WIN32) #include + +static HANDLE hallocy_heap = NULL; #elif defined(__linux__) #include #include @@ -35,7 +37,12 @@ typedef struct HallocyMemoryHeader { struct HallocyMemoryHeader *next; } HallocyMemoryHeader; +static _Thread_local size_t hallocy_small_memory_freed = 0; +static _Thread_local size_t hallocy_small_memory_allocated = 0; +static _Thread_local HallocyMemoryHeader *hallocy_small_memory_bin = NULL; + static size_t page_size = 0; +static size_t hallocy_small_allocation_size = 0; void *hallocy_malloc(size_t size) { if (page_size == 0) { @@ -45,20 +52,65 @@ void *hallocy_malloc(size_t size) { page_size = system_info.dwPageSize; #elif defined(__linux__) - page_size = sysconf(_SC_PAGESIZE); + page_size = sysconf(_SC_PAGE_SIZE); #endif + + hallocy_small_allocation_size = page_size; } size_t aligned_size = page_size * (((size + sizeof(HallocyMemoryHeader)) / page_size) + 1); HallocyMemoryHeader *memory_pointer = NULL; - #if defined(_WIN32) - memory_pointer = (HallocyMemoryHeader*)VirtualAlloc(NULL, aligned_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - #elif defined(__linux__) - memory_pointer = (HallocyMemoryHeader*)mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - #endif + if (aligned_size <= hallocy_small_allocation_size) { + HallocyMemoryHeader *previous_header = NULL; + memory_pointer = hallocy_small_memory_bin; + while (memory_pointer != NULL) { + if (memory_pointer->size >= aligned_size) { + hallocy_small_memory_allocated += memory_pointer->size; + hallocy_small_memory_freed -= memory_pointer->size; - if (memory_pointer == NULL) { - return NULL; + if (previous_header == NULL) { + hallocy_small_memory_bin = hallocy_small_memory_bin->next; + } else { + previous_header->next = memory_pointer->next; + } + + memory_pointer->next = NULL; + return (void*)(memory_pointer + 1); + } + + previous_header = memory_pointer; + memory_pointer = memory_pointer->next; + } + + #if defined(_WIN32) + if (hallocy_heap == NULL) { + hallocy_heap = GetProcessHeap(); + } + + memory_pointer = HeapAlloc(hallocy_heap, 0, aligned_size); + if (memory_pointer == NULL) { + return NULL; + } + #elif defined(__linux__) + memory_pointer = mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (memory_pointer == MAP_FAILED) { + return NULL; + } + #endif + + hallocy_small_memory_allocated += aligned_size; + } else { + #if defined(_WIN32) + memory_pointer = (HallocyMemoryHeader*)VirtualAlloc(NULL, aligned_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (memory_pointer == NULL) { + return NULL; + } + #elif defined(__linux__) + memory_pointer = (HallocyMemoryHeader*)mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (memory_pointer == MAP_FAILED) { + return NULL; + } + #endif } memory_pointer->size = aligned_size; @@ -73,45 +125,102 @@ HallocyError hallocy_free(void *pointer) { } HallocyMemoryHeader *memory_header = ((HallocyMemoryHeader*)pointer) - 1; - #if defined(_WIN32) - bool result = VirtualFree(memory_header, 0, MEM_RELEASE); - if (result == false) { - DWORD error = GetLastError(); - switch (error) { - case ERROR_INVALID_PARAMETER: - return HALLOCY_ERROR_INVALID_PARAM; + if (memory_header->size <= hallocy_small_allocation_size) { + memory_header->next = hallocy_small_memory_bin; + hallocy_small_memory_bin = memory_header; + + hallocy_small_memory_allocated -= memory_header->size; + hallocy_small_memory_freed += memory_header->size; + if (hallocy_small_memory_allocated == 0 && hallocy_small_memory_freed > hallocy_small_allocation_size * 10) { + HallocyMemoryHeader *previous_header = NULL; + HallocyMemoryHeader *current_header = hallocy_small_memory_bin; + while (current_header != NULL) { + previous_header = current_header; + current_header = current_header->next; - case ERROR_NOT_ENOUGH_MEMORY: - return HALLOCY_ERROR_OUT_OF_MEMORY; + #if defined(_WIN32) + bool result = HeapFree(hallocy_heap, 0, previous_header); + if (result == false) { + DWORD error = GetLastError(); + switch (error) { + case ERROR_INVALID_PARAMETER: + return HALLOCY_ERROR_INVALID_PARAM; + + case ERROR_NOT_ENOUGH_MEMORY: + return HALLOCY_ERROR_OUT_OF_MEMORY; + + case ERROR_INVALID_HANDLE: + return HALLOCY_ERROR_INVALID_POINTER; + + default: + return HALLOCY_ERROR_UNKNOWN; + } + } + #elif defined(__linux__) + int result = munmap(previous_header, previous_header->size); + if (result == -1) { + switch (errno) { + case EINVAL: + return HALLOCY_ERROR_INVALID_PARAM; + + case ENOMEM: + return HALLOCY_ERROR_OUT_OF_MEMORY; + + case EFAULT: + return HALLOCY_ERROR_INVALID_POINTER; + + default: + return HALLOCY_ERROR_UNKNOWN; + } + } + #endif + } - case ERROR_INVALID_HANDLE: - return HALLOCY_ERROR_INVALID_POINTER; - - case ERROR_INVALID_ADDRESS: - return HALLOCY_ERROR_INVALID_POINTER; - - default: - return HALLOCY_ERROR_UNKNOWN; + hallocy_small_memory_bin = NULL; + hallocy_small_memory_allocated = 0; + hallocy_small_memory_freed = 0; } - } - #elif defined(__linux__) - int result = munmap(memory_header, memory_header->size); - if (result == -1) { - switch (errno) { - case EINVAL: - return HALLOCY_ERROR_INVALID_PARAM; + } else { + #if defined(_WIN32) + bool result = VirtualFree(memory_header, 0, MEM_RELEASE); + if (result == false) { + DWORD error = GetLastError(); + switch (error) { + case ERROR_INVALID_PARAMETER: + return HALLOCY_ERROR_INVALID_PARAM; - case ENOMEM: - return HALLOCY_ERROR_OUT_OF_MEMORY; + case ERROR_NOT_ENOUGH_MEMORY: + return HALLOCY_ERROR_OUT_OF_MEMORY; - case EFAULT: - return HALLOCY_ERROR_INVALID_POINTER; + case ERROR_INVALID_HANDLE: + return HALLOCY_ERROR_INVALID_POINTER; - default: - return HALLOCY_ERROR_UNKNOWN; + case ERROR_INVALID_ADDRESS: + return HALLOCY_ERROR_INVALID_POINTER; + + default: + return HALLOCY_ERROR_UNKNOWN; + } } + #elif defined(__linux__) + int result = munmap(memory_header, memory_header->size); + if (result == -1) { + switch (errno) { + case EINVAL: + return HALLOCY_ERROR_INVALID_PARAM; + + case ENOMEM: + return HALLOCY_ERROR_OUT_OF_MEMORY; + + case EFAULT: + return HALLOCY_ERROR_INVALID_POINTER; + + default: + return HALLOCY_ERROR_UNKNOWN; + } + } + #endif } - #endif return HALLOCY_ERROR_NONE; } \ No newline at end of file