memory_linux.go raw

   1  //go:build linux && !(js && wasm)
   2  
   3  package ratelimit
   4  
   5  import (
   6  	"bufio"
   7  	"os"
   8  	"strconv"
   9  	"strings"
  10  )
  11  
  12  // ReadProcessMemoryStats reads memory statistics from /proc/self/status.
  13  // This provides accurate RSS (Resident Set Size) information on Linux,
  14  // including the breakdown between shared and anonymous memory.
  15  func ReadProcessMemoryStats() ProcessMemoryStats {
  16  	stats := ProcessMemoryStats{}
  17  
  18  	file, err := os.Open("/proc/self/status")
  19  	if err != nil {
  20  		// Fallback to runtime stats if /proc is not available
  21  		return readProcessMemoryStatsFallback()
  22  	}
  23  	defer file.Close()
  24  
  25  	scanner := bufio.NewScanner(file)
  26  	for scanner.Scan() {
  27  		line := scanner.Text()
  28  		fields := strings.Fields(line)
  29  		if len(fields) < 2 {
  30  			continue
  31  		}
  32  
  33  		key := strings.TrimSuffix(fields[0], ":")
  34  		valueStr := fields[1]
  35  
  36  		value, err := strconv.ParseUint(valueStr, 10, 64)
  37  		if err != nil {
  38  			continue
  39  		}
  40  
  41  		// Values in /proc/self/status are in kB
  42  		valueBytes := value * 1024
  43  
  44  		switch key {
  45  		case "VmRSS":
  46  			stats.VmRSS = valueBytes
  47  		case "RssShmem":
  48  			stats.RssShmem = valueBytes
  49  		case "RssAnon":
  50  			stats.RssAnon = valueBytes
  51  		case "VmHWM":
  52  			stats.VmHWM = valueBytes
  53  		}
  54  	}
  55  
  56  	// If we didn't get VmRSS, fall back to runtime stats
  57  	if stats.VmRSS == 0 {
  58  		return readProcessMemoryStatsFallback()
  59  	}
  60  
  61  	return stats
  62  }
  63