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 "internal/task"
11 "unsafe"
12 )
13 14 const needsStaticHeap = true
15 16 // Ever-incrementing pointer: no memory is freed.
17 var heapptr uintptr
18 19 // Total amount allocated for runtime.MemStats
20 var gcTotalAlloc uint64
21 22 // Total number of calls to alloc()
23 var gcMallocs uint64
24 25 // Heap lock for parallel goroutines. No-op when single threaded.
26 var gcLock task.PMutex
27 28 // Total number of objected freed; for leaking collector this stays 0
29 const gcFrees = 0
30 31 // Inlining alloc() speeds things up slightly but bloats the executable by 50%,
32 // see https://github.com/moxie-org/moxie/issues/2674. So don't.
33 //
34 //go:noinline
35 func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
36 // TODO: this can be optimized by not casting between pointers and ints so
37 // much. And by using platform-native data types (e.g. *uint8 for 8-bit
38 // systems).
39 gcLock.Lock()
40 size = align(size)
41 addr := heapptr
42 gcTotalAlloc += uint64(size)
43 gcMallocs++
44 heapptr += size
45 for heapptr >= heapEnd {
46 // Try to increase the heap and check again.
47 if growHeap() {
48 continue
49 }
50 // Failed to make the heap bigger, so we must really be out of memory.
51 runtimePanic("out of memory")
52 }
53 gcLock.Unlock()
54 55 pointer := unsafe.Pointer(addr)
56 zero_new_alloc(pointer, size)
57 return pointer
58 }
59 60 func realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer {
61 newAlloc := alloc(size, nil)
62 if ptr == nil {
63 return newAlloc
64 }
65 // according to POSIX everything beyond the previous pointer's
66 // size will have indeterminate values so we can just copy garbage
67 memcpy(newAlloc, ptr, size)
68 69 return newAlloc
70 }
71 72 func free(ptr unsafe.Pointer) {
73 // Memory is never freed.
74 }
75 76 func markRoots(start, end uintptr) {
77 runtimePanic("unreachable: markRoots")
78 }
79 80 // ReadMemStats populates m with memory statistics.
81 //
82 // The returned memory statistics are up to date as of the
83 // call to ReadMemStats. This would not do GC implicitly for you.
84 func ReadMemStats(m *MemStats) {
85 gcLock.Lock()
86 87 m.HeapIdle = 0
88 m.HeapInuse = gcTotalAlloc
89 m.HeapReleased = 0 // always 0, we don't currently release memory back to the OS.
90 91 m.HeapSys = m.HeapInuse + m.HeapIdle
92 m.GCSys = 0
93 m.TotalAlloc = gcTotalAlloc
94 m.Mallocs = gcMallocs
95 m.Frees = gcFrees
96 m.Sys = uint64(heapEnd - heapStart)
97 // no free -- current in use heap is the total allocated
98 m.HeapAlloc = gcTotalAlloc
99 m.Alloc = m.HeapAlloc
100 101 gcLock.Unlock()
102 }
103 104 func GC() {
105 // No-op.
106 }
107 108 func SetFinalizer(obj interface{}, finalizer interface{}) {
109 // No-op.
110 }
111 112 func initHeap() {
113 // Initialize this bump-pointer allocator to the start of the heap.
114 // Needed here because heapStart may not be a compile-time constant.
115 heapptr = heapStart
116 }
117 118 // setHeapEnd sets a new (larger) heapEnd pointer.
119 func setHeapEnd(newHeapEnd uintptr) {
120 // This "heap" is so simple that simply assigning a new value is good
121 // enough.
122 heapEnd = newHeapEnd
123 }
124