diff --git a/dnsfilter/dnsfilter.go b/dnsfilter/dnsfilter.go index 82b56187..6a79b79a 100644 --- a/dnsfilter/dnsfilter.go +++ b/dnsfilter/dnsfilter.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "runtime" + "runtime/debug" "strings" "sync" @@ -528,6 +529,9 @@ func (d *Dnsfilter) initFiltering(allowFilters, blockFilters []Filter) error { d.filteringEngine = filteringEngine d.rulesStorageWhite = rulesStorageWhite d.filteringEngineWhite = filteringEngineWhite + + // Make sure that the OS reclaims memory as soon as possible + debug.FreeOSMemory() log.Debug("initialized filtering engine") return nil diff --git a/main.go b/main.go index 36946082..449e3834 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,9 @@ package main import ( + "os" "runtime/debug" + "time" "github.com/AdguardTeam/AdGuardHome/home" ) @@ -16,6 +18,32 @@ var channel = "release" var goarm = "" func main() { - debug.SetGCPercent(10) + memoryUsage() + home.Main(version, channel, goarm) } + +// memoryUsage implements a couple of not really beautiful hacks which purpose is to +// make OS reclaim the memory freed by AdGuard Home as soon as possible. +func memoryUsage() { + debug.SetGCPercent(10) + + // madvdontneed: setting madvdontneed=1 will use MADV_DONTNEED + // instead of MADV_FREE on Linux when returning memory to the + // kernel. This is less efficient, but causes RSS numbers to drop + // more quickly. + _ = os.Setenv("GODEBUG", "madvdontneed=1") + + // periodically call "debug.FreeOSMemory" so + // that the OS could reclaim the free memory + go func() { + ticker := time.NewTicker(15 * time.Second) + for { + select { + case t := <-ticker.C: + t.Second() + debug.FreeOSMemory() + } + } + }() +}