mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
Use dynamic GOMEMLIMIT: 25% of system RAM, clamped to [2GB, 8GB]
Replace static 2GB default with platform-aware auto-detection: - Linux: syscall.Sysinfo - macOS: sysctl hw.memsize - Windows: GlobalMemoryStatusEx Falls back to 4GB if detection fails. User config still overrides. Prevents both OOM kills (upper clamp) and excessive GC pressure (lower clamp).
This commit is contained in:
1 parent
fac0c57359
commit
ba626aac50
5 files changed
+103
-7
No files matched your search
@@ -67,14 +67,17 @@ func main() {
|
||||
log.Fatalf("config err=%v", err)
|
||||
}
|
||||
|
||||
// Apply GOMEMLIMIT from config (e.g. "2G", "512M"), default 2GB.
|
||||
// Prevents OOM kills on systems without user-configured limits.
|
||||
memLimitStr := cfg.Get(store.ConfigMemLimit, "2G")
|
||||
if limit, parseErr := parseByteSize(memLimitStr); parseErr != nil {
|
||||
log.Printf("config: invalid mem_limit %q: %v", memLimitStr, parseErr)
|
||||
debug.SetMemoryLimit(2 << 30) // fallback: 2GB
|
||||
// Apply GOMEMLIMIT from config (e.g. "4G", "512M").
|
||||
// If not configured, auto-detect: 25% of system memory, clamped to [2GB, 8GB].
|
||||
// Prevents OOM kills while avoiding unnecessary GC pressure.
|
||||
if memLimitStr := cfg.Get(store.ConfigMemLimit, ""); memLimitStr != "" {
|
||||
if limit, parseErr := parseByteSize(memLimitStr); parseErr != nil {
|
||||
log.Printf("config: invalid mem_limit %q: %v", memLimitStr, parseErr)
|
||||
} else {
|
||||
debug.SetMemoryLimit(limit)
|
||||
}
|
||||
} else {
|
||||
debug.SetMemoryLimit(limit)
|
||||
debug.SetMemoryLimit(autoMemLimit())
|
||||
}
|
||||
|
||||
srv := tools.NewServer(router, tools.WithConfig(cfg))
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import "log"
|
||||
|
||||
const (
|
||||
minMemLimit int64 = 2 << 30 // 2 GB
|
||||
maxMemLimit int64 = 8 << 30 // 8 GB
|
||||
memFraction int64 = 4 // use 1/4 of system memory
|
||||
)
|
||||
|
||||
// autoMemLimit returns a GOMEMLIMIT value based on available system memory.
|
||||
// Uses 25% of total physical RAM, clamped to [2GB, 8GB].
|
||||
// Falls back to 4GB if detection fails.
|
||||
func autoMemLimit() int64 {
|
||||
total := totalSystemMemory()
|
||||
if total <= 0 {
|
||||
log.Printf("mem_limit: auto-detect unavailable, default=4GB")
|
||||
return 4 << 30
|
||||
}
|
||||
|
||||
limit := total / memFraction
|
||||
if limit < minMemLimit {
|
||||
limit = minMemLimit
|
||||
}
|
||||
if limit > maxMemLimit {
|
||||
limit = maxMemLimit
|
||||
}
|
||||
log.Printf("mem_limit: system=%dGB limit=%dGB", total>>30, limit>>30)
|
||||
return limit
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build darwin
|
||||
|
||||
package main
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
// totalSystemMemory returns total physical memory in bytes via sysctl hw.memsize.
|
||||
func totalSystemMemory() int64 {
|
||||
mem, err := unix.SysctlUint64("hw.memsize")
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return int64(mem)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build linux
|
||||
|
||||
package main
|
||||
|
||||
import "syscall"
|
||||
|
||||
// totalSystemMemory returns total physical memory in bytes via Sysinfo.
|
||||
func totalSystemMemory() int64 {
|
||||
var si syscall.Sysinfo_t
|
||||
if err := syscall.Sysinfo(&si); err != nil {
|
||||
return 0
|
||||
}
|
||||
return int64(si.Totalram) * int64(si.Unit)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// memoryStatusEx mirrors the Windows MEMORYSTATUSEX struct.
|
||||
type memoryStatusEx struct {
|
||||
length uint32
|
||||
memoryLoad uint32
|
||||
totalPhys uint64
|
||||
availPhys uint64
|
||||
totalPageFile uint64
|
||||
availPageFile uint64
|
||||
totalVirtual uint64
|
||||
availVirtual uint64
|
||||
availExtendedVirtual uint64
|
||||
}
|
||||
|
||||
// totalSystemMemory returns total physical memory via GlobalMemoryStatusEx.
|
||||
func totalSystemMemory() int64 {
|
||||
kernel32 := syscall.NewLazyDLL("kernel32.dll")
|
||||
proc := kernel32.NewProc("GlobalMemoryStatusEx")
|
||||
|
||||
var ms memoryStatusEx
|
||||
ms.length = uint32(unsafe.Sizeof(ms)) //nolint:gosec // standard Windows API pattern
|
||||
r, _, _ := proc.Call(uintptr(unsafe.Pointer(&ms)))
|
||||
if r == 0 {
|
||||
return 0
|
||||
}
|
||||
return int64(ms.totalPhys)
|
||||
}
|
||||
Reference in new issue
Block a user