Skip to content

Commit fefae7f

Browse files
committed
runtime: avoid zeroing scavenged memory
On Linux, memory returned to the kernel via MADV_DONTNEED is guaranteed to be zero-filled on its next use. This commit leverages this kernel behavior to avoid a redundant software zeroing pass in the runtime, improving performance. Signed-off-by: Lance Yang <[email protected]>
1 parent 12ec09f commit fefae7f

File tree

9 files changed

+47
-5
lines changed

9 files changed

+47
-5
lines changed

src/runtime/arena.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,12 @@ func (h *mheap) allocUserArenaChunk() *mspan {
10511051

10521052
// Model the user arena as a heap span for a large object.
10531053
spc := makeSpanClass(0, false)
1054-
h.initSpan(s, spanAllocHeap, spc, base, userArenaChunkPages)
1054+
1055+
// A user arena chunk is always fresh from the OS. It's either newly allocated
1056+
// via sysAlloc() or reused from the readyList after a sysFault(). The memory is
1057+
// then re-mapped via sysMap(), so we can safely treat it as scavenged; the
1058+
// kernel guarantees it will be zero-filled on its next use.
1059+
h.initSpan(s, spanAllocHeap, spc, base, userArenaChunkPages, userArenaChunkBytes)
10551060
s.isUserArenaChunk = true
10561061
s.elemsize -= userArenaChunkReserveBytes()
10571062
s.freeindex = 1

src/runtime/mem.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ func sysUnused(v unsafe.Pointer, n uintptr) {
7070
sysUnusedOS(v, n)
7171
}
7272

73+
// needZeroAfterSysUnused reports whether memory returned by sysUnused must be
74+
// zeroed for use.
75+
func needZeroAfterSysUnused() bool {
76+
return needZeroAfterSysUnusedOS()
77+
}
78+
7379
// sysUsed transitions a memory region from Prepared to Ready. It notifies the
7480
// operating system that the memory region is needed and ensures that the region
7581
// may be safely accessed. This is typically a no-op on systems that don't have

src/runtime/mem_aix.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,7 @@ func sysMapOS(v unsafe.Pointer, n uintptr, _ string) {
7979
throw("runtime: cannot map pages in arena address space")
8080
}
8181
}
82+
83+
func needZeroAfterSysUnusedOS() bool {
84+
return true
85+
}

src/runtime/mem_bsd.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,7 @@ func sysMapOS(v unsafe.Pointer, n uintptr, _ string) {
8585
throw("runtime: cannot map pages in arena address space")
8686
}
8787
}
88+
89+
func needZeroAfterSysUnusedOS() bool {
90+
return true
91+
}

src/runtime/mem_darwin.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,7 @@ func sysMapOS(v unsafe.Pointer, n uintptr, _ string) {
7474
throw("runtime: cannot map pages in arena address space")
7575
}
7676
}
77+
78+
func needZeroAfterSysUnusedOS() bool {
79+
return true
80+
}

src/runtime/mem_linux.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,7 @@ func sysMapOS(v unsafe.Pointer, n uintptr, vmaName string) {
188188
sysNoHugePageOS(v, n)
189189
}
190190
}
191+
192+
func needZeroAfterSysUnusedOS() bool {
193+
return debug.madvdontneed == 0
194+
}

src/runtime/mem_sbrk.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,3 +296,7 @@ func sysReserveAlignedSbrk(size, align uintptr) (unsafe.Pointer, uintptr) {
296296
})
297297
return unsafe.Pointer(p), size
298298
}
299+
300+
func needZeroAfterSysUnusedOS() bool {
301+
return true
302+
}

src/runtime/mem_windows.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,7 @@ func sysReserveOS(v unsafe.Pointer, n uintptr, _ string) unsafe.Pointer {
132132

133133
func sysMapOS(v unsafe.Pointer, n uintptr, _ string) {
134134
}
135+
136+
func needZeroAfterSysUnusedOS() bool {
137+
return true
138+
}

src/runtime/mheap.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,14 @@ func (h *mheap) setSpans(base, npage uintptr, s *mspan) {
10731073
// critical for future page allocations.
10741074
//
10751075
// There are no locking constraints on this method.
1076-
func (h *mheap) allocNeedsZero(base, npage uintptr) (needZero bool) {
1076+
func (h *mheap) allocNeedsZero(base, npage, scav uintptr) (needZero bool) {
1077+
// If these pages were scavenged (returned to the OS), the kernel guarantees
1078+
// they will be zero-filled on next use (fault-in), so we can treat them as
1079+
// already zeroed and skip explicit clearing.
1080+
if !needZeroAfterSysUnused() && scav == npage*pageSize {
1081+
return false
1082+
}
1083+
10771084
for npage > 0 {
10781085
ai := arenaIndex(base)
10791086
ha := h.arenas[ai.l1()][ai.l2()]
@@ -1394,7 +1401,7 @@ HaveSpan:
13941401
}
13951402

13961403
// Initialize the span.
1397-
h.initSpan(s, typ, spanclass, base, npages)
1404+
h.initSpan(s, typ, spanclass, base, npages, scav)
13981405

13991406
if valgrindenabled {
14001407
valgrindMempoolMalloc(unsafe.Pointer(arenaBase(arenaIndex(base))), unsafe.Pointer(base), npages*pageSize)
@@ -1440,11 +1447,11 @@ HaveSpan:
14401447

14411448
// initSpan initializes a blank span s which will represent the range
14421449
// [base, base+npages*pageSize). typ is the type of span being allocated.
1443-
func (h *mheap) initSpan(s *mspan, typ spanAllocType, spanclass spanClass, base, npages uintptr) {
1450+
func (h *mheap) initSpan(s *mspan, typ spanAllocType, spanclass spanClass, base, npages, scav uintptr) {
14441451
// At this point, both s != nil and base != 0, and the heap
14451452
// lock is no longer held. Initialize the span.
14461453
s.init(base, npages)
1447-
if h.allocNeedsZero(base, npages) {
1454+
if h.allocNeedsZero(base, npages, scav) {
14481455
s.needzero = 1
14491456
}
14501457
nbytes := npages * pageSize

0 commit comments

Comments
 (0)