When I use GODEBUG=madvdontneed=1 and FreeOSMemory, the memory not being reclaimed by OS for long time, why?

No goroutine leak.
Around some code path which does frequent memory allocation and release, the memory not being reclaimed by OS, even I stop the test for long time.
GoVersion: go1.20.3
curl | less

After I set runtime.MemProfileRate = 1
curl | less

heap profile: 982711: 384712832 [306603837: 49470010600] @ heap/2

# runtime.MemStats
# Alloc = 469250056
# TotalAlloc = 49938819968
# Sys = 3191753112
# Lookups = 0
# Mallocs = 347135802
# Frees = 345386293
# HeapAlloc = 469250056
# HeapSys = 2800910336
# HeapIdle = 2318524416
# HeapInuse = 482385920
# HeapReleased = 1903173632
# HeapObjects = 1749509
# Stack = 5079040 / 5079040
# MSpan = 3365920 / 16238400
# MCache = 48000 / 62400
# BuckHashSys = 23255276
# GCSys = 64164064
# OtherSys = 282043596
# NextGC = 782366512
# LastGC = 1689328547695610282

  1. Why HeapInuse(482385920) not equal to 384712832 and HeapObjects(1749509) not equal to 982711?
  2. How can I know who reference the memory?

It seems that locating memory leaks in Golang is more difficult than in C++…

The GODEBUG environment variable in Golang provides various debugging options, including the madvdontneed=1 flag. When this flag is set, it advises the operating system to not reclaim memory pages that have been recently freed by the Go runtime. The purpose of this flag is to improve performance by reducing the overhead of releasing memory to the operating system.

However, setting madvdontneed=1 and using FreeOSMemory can indeed cause memory to be held by the Go runtime for a longer time. When you explicitly release memory using runtime.FreeOSMemory(), the Go runtime may still retain some memory for future allocations to avoid frequent system calls for memory allocation and deallocation.

The Go runtime manages its own memory allocation and garbage collection, and it has its own heuristics for deciding when to release memory to the operating system. By default, the Go runtime tries to strike a balance between keeping memory for future allocations and releasing memory back to the operating system.

If you find that memory is not being reclaimed by the operating system for an extended period, it is likely due to the behavior of the Go runtime and its memory management algorithms. This behavior can vary depending on the Go version, operating system, and other factors.

If you’re facing specific memory-related issues, such as excessive memory usage or memory leaks, it’s recommended to analyze and optimize your code and ensure that you’re using resources efficiently. The Go profiler (go tool pprof) can be helpful in identifying memory usage patterns and optimizing memory-intensive parts of your code.

In general, it’s important to be mindful when using advanced memory management options like madvdontneed=1 and FreeOSMemory. They provide control and performance improvements, but they may also have side effects that require careful consideration in your specific use case.

Is there a way to ignore the behavior of Go runtime and force release memory, so that I can determine if there is a memory leak?