diff --git a/source/runtime.c b/source/runtime.c index aa3b30f1..56de2c58 100644 --- a/source/runtime.c +++ b/source/runtime.c @@ -728,10 +728,16 @@ void *js_malloc (JSContext *ctx, size_t size) { The second GC is cheap: data was just compacted so there is almost no garbage to skip. */ if ((uint8_t *)ctx->heap_free + size > (uint8_t *)ctx->heap_end) { - size_t need = (size_t)((uint8_t *)ctx->heap_free - (uint8_t *)ctx->heap_base) + size; + size_t live = (size_t)((uint8_t *)ctx->heap_free - (uint8_t *)ctx->heap_base); + size_t need = live + size; size_t ns = ctx->current_block_size; while (ns < need && ns < (1ULL << BUDDY_MAX_ORDER)) ns *= 2; +#ifdef DUMP_GC + printf (" growing %zu -> %zu for %zu byte alloc (live %zu)\n", + ctx->current_block_size, ns, size, live); + fflush (stdout); +#endif ctx->next_block_size = ns; if (ctx_gc (ctx, 1, size) < 0) { JS_ThrowOutOfMemory (ctx); @@ -1332,7 +1338,7 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) { #ifdef DUMP_GC int will_grow = 0; #endif - if (allow_grow && old_used > 0 && recovered < old_used / 5) { + if (allow_grow && recovered > 0 && old_used > 0 && recovered < old_used / 5) { size_t doubled = new_size * 2; if (doubled <= (1ULL << BUDDY_MAX_ORDER)) { ctx->next_block_size = doubled; @@ -1343,15 +1349,42 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) { } #ifdef DUMP_GC - printf ("\nGC: %zu -> %zu bytes (used %zu -> %zu), recovered %zu (%.1f%%)%s\n", - old_heap_size, - new_size, - old_used, - new_used, - recovered, - old_used > 0 ? (recovered * 100.0 / old_used) : 0.0, - will_grow ? ", heap will grow" : ""); - fflush(stdout); + { + /* Walk to-space and tally memory by object type */ + static const char *type_names[] = { + [OBJ_ARRAY] = "array", + [OBJ_TEXT] = "text", + [OBJ_RECORD] = "record", + [OBJ_FUNCTION] = "function", + [OBJ_FRAME] = "frame", + }; + size_t type_bytes[8] = {0}; + size_t type_count[8] = {0}; + uint8_t *p = to_base; + while (p < to_free) { + uint8_t t = objhdr_type (*(objhdr_t *)p); + size_t sz = gc_object_size (p); + type_bytes[t] += sz; + type_count[t]++; + p += sz; + } + + printf ("\nGC: %zu -> %zu bytes, recovered %zu (%.1f%%)%s\n", + old_heap_size, + new_size, + recovered, + old_used > 0 ? (recovered * 100.0 / old_used) : 0.0, + will_grow ? ", will grow (poor recovery)" : ""); + printf (" live %zu / %zu bytes (%.0f%% full):", + new_used, new_size, + new_size > 0 ? (new_used * 100.0 / new_size) : 0.0); + for (int i = 0; i < 7; i++) { + if (type_count[i] == 0) continue; + printf (" %s %zu(%zu)", type_names[i], type_bytes[i], type_count[i]); + } + printf ("\n"); + fflush (stdout); + } #endif return 0;