github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/gc_leaking.go (about) 1 //go:build gc.leaking 2 3 package runtime 4 5 // This GC implementation is the simplest useful memory allocator possible: it 6 // only allocates memory and never frees it. For some constrained systems, it 7 // may be the only memory allocator possible. 8 9 import ( 10 "unsafe" 11 ) 12 13 // Ever-incrementing pointer: no memory is freed. 14 var heapptr = heapStart 15 16 // Total amount allocated for runtime.MemStats 17 var gcTotalAlloc uint64 18 19 // Total number of calls to alloc() 20 var gcMallocs uint64 21 22 // Total number of objected freed; for leaking collector this stays 0 23 const gcFrees = 0 24 25 // Inlining alloc() speeds things up slightly but bloats the executable by 50%, 26 // see https://github.com/tinygo-org/tinygo/issues/2674. So don't. 27 // 28 //go:noinline 29 func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer { 30 // TODO: this can be optimized by not casting between pointers and ints so 31 // much. And by using platform-native data types (e.g. *uint8 for 8-bit 32 // systems). 33 size = align(size) 34 addr := heapptr 35 gcTotalAlloc += uint64(size) 36 gcMallocs++ 37 heapptr += size 38 for heapptr >= heapEnd { 39 // Try to increase the heap and check again. 40 if growHeap() { 41 continue 42 } 43 // Failed to make the heap bigger, so we must really be out of memory. 44 runtimePanic("out of memory") 45 } 46 pointer := unsafe.Pointer(addr) 47 memzero(pointer, size) 48 return pointer 49 } 50 51 func realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer { 52 newAlloc := alloc(size, nil) 53 if ptr == nil { 54 return newAlloc 55 } 56 // according to POSIX everything beyond the previous pointer's 57 // size will have indeterminate values so we can just copy garbage 58 memcpy(newAlloc, ptr, size) 59 60 return newAlloc 61 } 62 63 func free(ptr unsafe.Pointer) { 64 // Memory is never freed. 65 } 66 67 // ReadMemStats populates m with memory statistics. 68 // 69 // The returned memory statistics are up to date as of the 70 // call to ReadMemStats. This would not do GC implicitly for you. 71 func ReadMemStats(m *MemStats) { 72 m.HeapIdle = 0 73 m.HeapInuse = gcTotalAlloc 74 m.HeapReleased = 0 // always 0, we don't currently release memory back to the OS. 75 76 m.HeapSys = m.HeapInuse + m.HeapIdle 77 m.GCSys = 0 78 m.TotalAlloc = gcTotalAlloc 79 m.Mallocs = gcMallocs 80 m.Frees = gcFrees 81 m.Sys = uint64(heapEnd - heapStart) 82 } 83 84 func GC() { 85 // No-op. 86 } 87 88 func SetFinalizer(obj interface{}, finalizer interface{}) { 89 // No-op. 90 } 91 92 func initHeap() { 93 // preinit() may have moved heapStart; reset heapptr 94 heapptr = heapStart 95 } 96 97 // setHeapEnd sets a new (larger) heapEnd pointer. 98 func setHeapEnd(newHeapEnd uintptr) { 99 // This "heap" is so simple that simply assigning a new value is good 100 // enough. 101 heapEnd = newHeapEnd 102 }