diff --git a/config/config.go b/config/config.go index 5a20e257b73..83585146605 100644 --- a/config/config.go +++ b/config/config.go @@ -24,6 +24,10 @@ type Configuration struct { CacheClient HTTPClient `mapstructure:"http_client_cache"` AdminPort int `mapstructure:"admin_port"` EnableGzip bool `mapstructure:"enable_gzip"` + // GarbageCollectorThreshold allocates virtual memory (in bytes) which is not used by PBS but + // serves as a hack to trigger the garbage collector only when the heap reaches at least this size. + // More info: https://github.com/golang/go/issues/48409 + GarbageCollectorThreshold int `mapstructure:"garbage_collector_threshold"` // StatusResponse is the string which will be returned by the /status endpoint when things are OK. // If empty, it will return a 204 with no content. StatusResponse string `mapstructure:"status_response"` @@ -634,6 +638,7 @@ func SetupViper(v *viper.Viper, filename string) { v.SetDefault("port", 8000) v.SetDefault("admin_port", 6060) v.SetDefault("enable_gzip", false) + v.SetDefault("garbage_collector_threshold", 0) v.SetDefault("status_response", "") v.SetDefault("auction_timeouts_ms.default", 0) v.SetDefault("auction_timeouts_ms.max", 0) diff --git a/config/config_test.go b/config/config_test.go index 9e9c70375e4..f86f13bda7c 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -289,6 +289,7 @@ external_url: http://prebid-server.prebid.org/ host: prebid-server.prebid.org port: 1234 admin_port: 5678 +garbage_collector_threshold: 1 auction_timeouts_ms: max: 123 default: 50 @@ -426,6 +427,7 @@ func TestFullConfig(t *testing.T) { cmpStrings(t, "host", cfg.Host, "prebid-server.prebid.org") cmpInts(t, "port", cfg.Port, 1234) cmpInts(t, "admin_port", cfg.AdminPort, 5678) + cmpInts(t, "garbage_collector_threshold", cfg.GarbageCollectorThreshold, 1) cmpInts(t, "auction_timeouts_ms.default", int(cfg.AuctionTimeouts.Default), 50) cmpInts(t, "auction_timeouts_ms.max", int(cfg.AuctionTimeouts.Max), 123) cmpStrings(t, "cache.scheme", cfg.CacheURL.Scheme, "http") diff --git a/main.go b/main.go index 76fa64f77ef..c103863107d 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "flag" "math/rand" "net/http" + "runtime" "time" "github.com/prebid/prebid-server/config" @@ -28,6 +29,14 @@ func main() { glog.Exitf("Configuration could not be loaded or did not pass validation: %v", err) } + // Create a soft memory limit on the total amount of memory that PBS uses to tune the behavior + // of the Go garbage collector. In summary, `cfg.GarbageCollectorThreshold` serves as a fixed cost + // of memory that is going to be held garbage before a garbage collection cycle is triggered. + // This amount of virtual memory won’t translate into physical memory allocation unless we attempt + // to read or write to the slice below, which PBS will not do. + garbageCollectionThreshold := make([]byte, cfg.GarbageCollectorThreshold) + defer runtime.KeepAlive(garbageCollectionThreshold) + err = serve(cfg) if err != nil { glog.Exitf("prebid-server failed: %v", err)