fixed: memory leaks
added: memory cache for GLIB arrays and hashtables
This commit is contained in:
parent
7f0ca78f92
commit
150f87990a
|
@ -179,11 +179,11 @@ void print_help(void) {
|
||||||
" --mode=[app|lib] set the compilation mode to either application or library",
|
" --mode=[app|lib] set the compilation mode to either application or library",
|
||||||
" --output=name name of output files without extension",
|
" --output=name name of output files without extension",
|
||||||
"Options:",
|
"Options:",
|
||||||
" --verbose print logs with level information or higher",
|
" --verbose print logs with level information or higher",
|
||||||
" --debug print debug logs (if not disabled at compile time)",
|
" --debug print debug logs (if not disabled at compile time)",
|
||||||
" --version print the version",
|
" --version print the version",
|
||||||
" --help print this hel dialog",
|
" --help print this hel dialog",
|
||||||
" --print-memory-stats print statistics of the garbage collector"
|
" --print-gc-stats print statistics of the garbage collector"
|
||||||
};
|
};
|
||||||
|
|
||||||
for (unsigned int i = 0; i < sizeof(lines) / sizeof(const char *); i++) {
|
for (unsigned int i = 0; i < sizeof(lines) / sizeof(const char *); i++) {
|
||||||
|
|
|
@ -142,12 +142,10 @@ static void build_target(ModuleFileStack *unit, const TargetConfig *target) {
|
||||||
if (setup_target_environment(target) == 0) {
|
if (setup_target_environment(target) == 0) {
|
||||||
|
|
||||||
print_ast_to_file(ast, target);
|
print_ast_to_file(ast, target);
|
||||||
Module * test = create_set(ast);
|
Module* test = create_set(ast);
|
||||||
|
|
||||||
// TODO: parse AST to semantic values
|
// TODO: parse AST to semantic values
|
||||||
// TODO: backend codegen
|
// TODO: backend codegen
|
||||||
|
|
||||||
delete_set(test);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
run_compiler();
|
run_compiler();
|
||||||
|
|
||||||
if (is_option_set("print-memory-stats")) {
|
if (is_option_set("print-gc-stats")) {
|
||||||
print_memory_statistics();
|
print_memory_statistics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
102
src/mem/cache.c
102
src/mem/cache.c
|
@ -7,6 +7,7 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <cfg/opt.h>
|
||||||
|
|
||||||
static GHashTable* namespaces = NULL;
|
static GHashTable* namespaces = NULL;
|
||||||
|
|
||||||
|
@ -20,6 +21,17 @@ typedef struct MemoryNamespaceStatistic_t {
|
||||||
size_t purged_free_count;
|
size_t purged_free_count;
|
||||||
} MemoryNamespaceStatistic;
|
} MemoryNamespaceStatistic;
|
||||||
|
|
||||||
|
typedef enum MemoryBlockType_t {
|
||||||
|
GenericBlock,
|
||||||
|
GLIB_Array,
|
||||||
|
GLIB_HashTable
|
||||||
|
} MemoryBlockType;
|
||||||
|
|
||||||
|
typedef struct MemoryBlock_t {
|
||||||
|
void* block_ptr;
|
||||||
|
MemoryBlockType kind;
|
||||||
|
} MemoryBlock;
|
||||||
|
|
||||||
typedef struct MemoryNamespace_t {
|
typedef struct MemoryNamespace_t {
|
||||||
MemoryNamespaceStatistic statistic;
|
MemoryNamespaceStatistic statistic;
|
||||||
GArray* blocks;
|
GArray* blocks;
|
||||||
|
@ -44,9 +56,11 @@ static void* namespace_malloc(MemoryNamespaceRef memoryNamespace, size_t size) {
|
||||||
assert(memoryNamespace != NULL);
|
assert(memoryNamespace != NULL);
|
||||||
assert(size != 0);
|
assert(size != 0);
|
||||||
|
|
||||||
void* block = malloc(size);
|
MemoryBlock block;
|
||||||
|
block.block_ptr = malloc(size);
|
||||||
|
block.kind = GenericBlock;
|
||||||
|
|
||||||
if (block == NULL) {
|
if (block.block_ptr == NULL) {
|
||||||
memoryNamespace->statistic.faulty_allocations ++;
|
memoryNamespace->statistic.faulty_allocations ++;
|
||||||
} else {
|
} else {
|
||||||
g_array_append_val(memoryNamespace->blocks, block);
|
g_array_append_val(memoryNamespace->blocks, block);
|
||||||
|
@ -55,20 +69,36 @@ static void* namespace_malloc(MemoryNamespaceRef memoryNamespace, size_t size) {
|
||||||
memoryNamespace->statistic.bytes_allocated += size;
|
memoryNamespace->statistic.bytes_allocated += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return block;
|
return block.block_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void namespace_free_block(MemoryBlock block) {
|
||||||
|
switch (block.kind) {
|
||||||
|
case GenericBlock:
|
||||||
|
free(block.block_ptr);
|
||||||
|
break;
|
||||||
|
case GLIB_Array:
|
||||||
|
g_array_free(block.block_ptr, TRUE);
|
||||||
|
break;
|
||||||
|
case GLIB_HashTable:
|
||||||
|
g_hash_table_destroy(block.block_ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean namespace_free(MemoryNamespaceRef memoryNamespace, void* block) {
|
static gboolean namespace_free(MemoryNamespaceRef memoryNamespace, void* block) {
|
||||||
for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
|
for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
|
||||||
void* current_block = g_array_index(memoryNamespace->blocks, void*, i);
|
MemoryBlock current_block = g_array_index(memoryNamespace->blocks, MemoryBlock, i);
|
||||||
|
|
||||||
if (current_block == block) {
|
if (current_block.block_ptr == block) {
|
||||||
assert(block != NULL);
|
assert(block != NULL);
|
||||||
|
|
||||||
free(block);
|
namespace_free_block(current_block);
|
||||||
|
|
||||||
g_array_remove_index(memoryNamespace->blocks, i);
|
g_array_remove_index(memoryNamespace->blocks, i);
|
||||||
|
|
||||||
memoryNamespace->statistic.manual_free_count++;
|
memoryNamespace->statistic.manual_free_count++;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,13 +109,13 @@ static void* namespace_realloc(MemoryNamespaceRef memoryNamespace, void* block,
|
||||||
void* reallocated_block = NULL;
|
void* reallocated_block = NULL;
|
||||||
|
|
||||||
for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
|
for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
|
||||||
void* current_block = g_array_index(memoryNamespace->blocks, void*, i);
|
MemoryBlock current_block = g_array_index(memoryNamespace->blocks, MemoryBlock, i);
|
||||||
|
|
||||||
if (current_block == block) {
|
if (current_block.block_ptr == block) {
|
||||||
reallocated_block = realloc(block, size);
|
reallocated_block = realloc(current_block.block_ptr, size);
|
||||||
|
|
||||||
if (reallocated_block != NULL) {
|
if (reallocated_block != NULL) {
|
||||||
g_array_index(memoryNamespace->blocks, void*, i) = reallocated_block;
|
g_array_index(memoryNamespace->blocks, MemoryBlock, i).block_ptr = reallocated_block;
|
||||||
memoryNamespace->statistic.bytes_allocated += size;
|
memoryNamespace->statistic.bytes_allocated += size;
|
||||||
memoryNamespace->statistic.reallocation_count ++;
|
memoryNamespace->statistic.reallocation_count ++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -107,9 +137,9 @@ static void namespace_delete(MemoryNamespaceRef memoryNamespace) {
|
||||||
static void namespace_purge(MemoryNamespaceRef memoryNamespace) {
|
static void namespace_purge(MemoryNamespaceRef memoryNamespace) {
|
||||||
|
|
||||||
for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
|
for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
|
||||||
void* current_block = g_array_index(memoryNamespace->blocks, void*, i);
|
MemoryBlock current_block = g_array_index(memoryNamespace->blocks, MemoryBlock, i);
|
||||||
|
|
||||||
free(current_block);
|
namespace_free_block(current_block);
|
||||||
|
|
||||||
memoryNamespace->statistic.purged_free_count ++;
|
memoryNamespace->statistic.purged_free_count ++;
|
||||||
}
|
}
|
||||||
|
@ -120,7 +150,7 @@ static void namespace_purge(MemoryNamespaceRef memoryNamespace) {
|
||||||
static MemoryNamespaceRef namespace_new() {
|
static MemoryNamespaceRef namespace_new() {
|
||||||
MemoryNamespaceRef memoryNamespace = malloc(sizeof(MemoryNamespace));
|
MemoryNamespaceRef memoryNamespace = malloc(sizeof(MemoryNamespace));
|
||||||
|
|
||||||
memoryNamespace->blocks = g_array_new(FALSE, FALSE, sizeof(void*));
|
memoryNamespace->blocks = g_array_new(FALSE, FALSE, sizeof(MemoryBlock));
|
||||||
memoryNamespace->statistic.bytes_allocated = 0;
|
memoryNamespace->statistic.bytes_allocated = 0;
|
||||||
memoryNamespace->statistic.allocation_count = 0;
|
memoryNamespace->statistic.allocation_count = 0;
|
||||||
memoryNamespace->statistic.manual_free_count = 0;
|
memoryNamespace->statistic.manual_free_count = 0;
|
||||||
|
@ -132,6 +162,30 @@ static MemoryNamespaceRef namespace_new() {
|
||||||
return memoryNamespace;
|
return memoryNamespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GArray *namespace_new_g_array(MemoryNamespaceRef namespace, guint size) {
|
||||||
|
MemoryBlock block;
|
||||||
|
block.block_ptr = g_array_new(FALSE, FALSE, size);
|
||||||
|
block.kind = GLIB_Array;
|
||||||
|
|
||||||
|
g_array_append_val(namespace->blocks, block);
|
||||||
|
namespace->statistic.bytes_allocated += sizeof(GArray*);
|
||||||
|
namespace->statistic.allocation_count ++;
|
||||||
|
|
||||||
|
return block.block_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
GHashTable *namespace_new_g_hash_table(MemoryNamespaceRef namespace, GHashFunc hash_func, GEqualFunc key_equal_func) {
|
||||||
|
MemoryBlock block;
|
||||||
|
block.block_ptr = g_hash_table_new(hash_func, key_equal_func);
|
||||||
|
block.kind = GLIB_HashTable;
|
||||||
|
|
||||||
|
g_array_append_val(namespace->blocks, block);
|
||||||
|
namespace->statistic.bytes_allocated += sizeof(GHashTable*);
|
||||||
|
namespace->statistic.allocation_count ++;
|
||||||
|
|
||||||
|
return block.block_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
static void cleanup() {
|
static void cleanup() {
|
||||||
if (namespaces == NULL) {
|
if (namespaces == NULL) {
|
||||||
printf("==> Memory cache was unused <==\n");
|
printf("==> Memory cache was unused <==\n");
|
||||||
|
@ -267,5 +321,25 @@ void print_memory_statistics() {
|
||||||
|
|
||||||
namespace_statistics_print(&total, "summary");
|
namespace_statistics_print(&total, "summary");
|
||||||
|
|
||||||
printf("Note: untracked are memory allocations from external libraries.\n");
|
printf("Note: untracked are memory allocations from external libraries and non-gc managed components.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
GArray* mem_new_g_array(MemoryNamespaceName name, guint element_size) {
|
||||||
|
MemoryNamespaceRef cache = check_namespace(name);
|
||||||
|
|
||||||
|
if (cache == NULL) {
|
||||||
|
PANIC("memory namespace not created");
|
||||||
|
}
|
||||||
|
|
||||||
|
return namespace_new_g_array(cache, element_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
GHashTable* mem_new_g_hash_table(MemoryNamespaceName name, GHashFunc hash_func, GEqualFunc key_equal_func) {
|
||||||
|
MemoryNamespaceRef cache = check_namespace(name);
|
||||||
|
|
||||||
|
if (cache == NULL) {
|
||||||
|
PANIC("memory namespace not created");
|
||||||
|
}
|
||||||
|
|
||||||
|
return namespace_new_g_hash_table(cache, hash_func, key_equal_func);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <mem/cache.h>
|
#include <mem/cache.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
typedef char* MemoryNamespaceName;
|
typedef char* MemoryNamespaceName;
|
||||||
|
|
||||||
|
@ -86,4 +87,8 @@ void* mem_clone(MemoryNamespaceName name, void* data, size_t size);
|
||||||
|
|
||||||
void print_memory_statistics();
|
void print_memory_statistics();
|
||||||
|
|
||||||
|
GArray* mem_new_g_array(MemoryNamespaceName name, guint element_size);
|
||||||
|
|
||||||
|
GHashTable* mem_new_g_hash_table(MemoryNamespaceName name, GHashFunc hash_func, GEqualFunc key_equal_func);
|
||||||
|
|
||||||
#endif //GEMSTONE_CACHE_H
|
#endif //GEMSTONE_CACHE_H
|
||||||
|
|
1412
src/set/set.c
1412
src/set/set.c
File diff suppressed because it is too large
Load Diff
186
src/set/types.c
186
src/set/types.c
|
@ -1,186 +0,0 @@
|
||||||
//
|
|
||||||
// Created by servostar on 6/7/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <mem/cache.h>
|
|
||||||
#include <set/types.h>
|
|
||||||
|
|
||||||
void delete_box(BoxType *box) {
|
|
||||||
g_hash_table_destroy(box->member);
|
|
||||||
mem_free(box);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void delete_box_table(GHashTable *box_table) {
|
|
||||||
GHashTableIter iter;
|
|
||||||
char *name = NULL;
|
|
||||||
BoxType *box = NULL;
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, box_table);
|
|
||||||
|
|
||||||
while (g_hash_table_iter_next(&iter, (gpointer)&name, (gpointer)&box)) {
|
|
||||||
delete_box(box);
|
|
||||||
mem_free(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_hash_table_destroy(box_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void delete_imports(GArray *imports) { g_array_free(imports, TRUE); }
|
|
||||||
|
|
||||||
void delete_box_member(BoxMember *member) {
|
|
||||||
member->box = NULL;
|
|
||||||
delete_expression(member->initalizer);
|
|
||||||
delete_type(member->type);
|
|
||||||
mem_free((void *)member->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete_box_type(BoxType *box_type) {
|
|
||||||
GHashTableIter iter;
|
|
||||||
char *name = NULL;
|
|
||||||
BoxMember *member = NULL;
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, box_type->member);
|
|
||||||
|
|
||||||
while (g_hash_table_iter_next(&iter, (gpointer)&name, (gpointer)&member)) {
|
|
||||||
delete_box_member(member);
|
|
||||||
mem_free(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_hash_table_destroy(box_type->member);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete_composite([[maybe_unused]] CompositeType *composite) {}
|
|
||||||
|
|
||||||
void delete_type(Type *type) {
|
|
||||||
switch (type->kind) {
|
|
||||||
case TypeKindBox:
|
|
||||||
delete_box_type(&type->impl.box);
|
|
||||||
break;
|
|
||||||
case TypeKindReference:
|
|
||||||
delete_type(type->impl.reference);
|
|
||||||
break;
|
|
||||||
case TypeKindPrimitive:
|
|
||||||
break;
|
|
||||||
case TypeKindComposite:
|
|
||||||
delete_composite(&type->impl.composite);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void delete_type_table(GHashTable *type_table) {
|
|
||||||
|
|
||||||
GHashTableIter iter;
|
|
||||||
char *name = NULL;
|
|
||||||
Type *type = NULL;
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, type_table);
|
|
||||||
|
|
||||||
while (g_hash_table_iter_next(&iter, (gpointer)&name, (gpointer)&type)) {
|
|
||||||
delete_type(type);
|
|
||||||
mem_free(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_hash_table_destroy(type_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete_box_access(BoxAccess *access) {
|
|
||||||
delete_variable(access->variable);
|
|
||||||
|
|
||||||
for (guint i = 0; i < access->member->len; i++) {
|
|
||||||
delete_box_member(g_array_index(access->member, BoxMember *, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
g_array_free(access->member, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete_variable(Variable *variable) {
|
|
||||||
switch (variable->kind) {
|
|
||||||
case VariableKindBoxMember:
|
|
||||||
delete_box_access(&variable->impl.member);
|
|
||||||
break;
|
|
||||||
case VariableKindDeclaration:
|
|
||||||
delete_declaration(&variable->impl.declaration);
|
|
||||||
break;
|
|
||||||
case VariableKindDefinition:
|
|
||||||
delete_definition(&variable->impl.definiton);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete_declaration(VariableDeclaration *decl) { delete_type(decl->type); }
|
|
||||||
|
|
||||||
void delete_definition(VariableDefiniton *definition) {
|
|
||||||
delete_declaration(&definition->declaration);
|
|
||||||
delete_expression(definition->initializer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete_type_value(TypeValue *value) {
|
|
||||||
delete_type(value->type);
|
|
||||||
mem_free(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete_operation(Operation *operation) {
|
|
||||||
for (guint i = 0; i < operation->operands->len; i++) {
|
|
||||||
delete_expression(g_array_index(operation->operands, Expression *, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
g_array_free(operation->operands, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete_transmute(Transmute *trans) {
|
|
||||||
delete_expression(trans->operand);
|
|
||||||
delete_type(trans->targetType);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete_typecast(TypeCast *cast) {
|
|
||||||
delete_expression(cast->operand);
|
|
||||||
delete_type(cast->targetType);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete_expression(Expression *expr) {
|
|
||||||
delete_type(expr->result);
|
|
||||||
|
|
||||||
switch (expr->kind) {
|
|
||||||
case ExpressionKindConstant:
|
|
||||||
delete_type_value(&expr->impl.constant);
|
|
||||||
break;
|
|
||||||
case ExpressionKindOperation:
|
|
||||||
delete_operation(&expr->impl.operation);
|
|
||||||
break;
|
|
||||||
case ExpressionKindTransmute:
|
|
||||||
delete_transmute(&expr->impl.transmute);
|
|
||||||
break;
|
|
||||||
case ExpressionKindTypeCast:
|
|
||||||
delete_typecast(&expr->impl.typecast);
|
|
||||||
break;
|
|
||||||
case ExpressionKindVariable:
|
|
||||||
delete_variable(expr->impl.variable);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void delete_variable_table(GHashTable *variable_table) {
|
|
||||||
|
|
||||||
GHashTableIter iter;
|
|
||||||
char *name = NULL;
|
|
||||||
Variable *variable = NULL;
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, variable_table);
|
|
||||||
|
|
||||||
while (g_hash_table_iter_next(&iter, (gpointer)&name, (gpointer)&variable)) {
|
|
||||||
delete_variable(variable);
|
|
||||||
mem_free(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_hash_table_destroy(variable_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete_module(Module *module) {
|
|
||||||
|
|
||||||
delete_box_table(module->boxes);
|
|
||||||
delete_imports(module->imports);
|
|
||||||
delete_type_table(module->types);
|
|
||||||
delete_variable_table(module->variables);
|
|
||||||
|
|
||||||
mem_free(module);
|
|
||||||
}
|
|
Loading…
Reference in New Issue