OOMProf is an eBPF-based process monitor that automatically captures heap profiles from Go programs just before they are killed by the Linux Out-of-Memory (OOM) killer, or on-demand for specific processes. This enables post-mortem analysis of memory usage patterns that led to OOM conditions.
-p flagOOMProf uses eBPF tracepoints to monitor kernel OOM killer events and automatically:
oom/mark_victim tracepointsignal/signal_deliver tracepointThe captured profiles show memory allocation patterns, call stacks, and heap usage that can help identify memory leaks, excessive allocations, or other issues that led to the OOM condition.
# Clone the repository
git clone https://github.com/parca-dev/oomprof.git
cd oomprof
# Build the binaries
make
This creates:
oompa - Main OOMProf monitor (OOM Profiler Agent)tests/oomer.taux - Test binary for generating OOM conditionstests/gccache.taux - Test binary for GC cache stress testingoomprof.test - Test suiteRun OOMProf as root to monitor all Go processes:
sudo ./oompa
When a Go process is OOM killed, oompa will automatically generate a profile file named {command}-{pid}.pb.gz.
Profile specific processes by PID using the -p flag with comma-delimited PIDs:
# Profile a single process
sudo ./oompa -p 1234
# Profile multiple processes
sudo ./oompa -p 1234,5678,9012
This will generate profile files for each specified PID and exit once profiling is complete.
View the captured profile using Go's pprof tool:
# Interactive analysis
go tool pprof {command}-{pid}.pb.gz
# Generate a web interface
go tool pprof -http=:8080 {command}-{pid}.pb.gz
# View top memory consumers
go tool pprof -top {command}-{pid}.pb.gz
OOMProf can be used as a library in your own applications:
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/parca-dev/oomprof/oomprof"
)
func main() {
profileChan := make(chan oomprof.ProfileData)
state, err := oomprof.Setup(context.Background(), &oomprof.Config{}, profileChan)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to setup OOM profiler: %v\n", err)
os.Exit(1)
}
defer state.Close()
for profile := range profileChan {
// Create filename with timestamp: command-pid-YYYYMMDDHHmmss.pb.gz
timestamp := time.Now().Format("20060102150405")
filename := fmt.Sprintf("%s-%d-%s.pb.gz", profile.Command, profile.PID, timestamp)
f, err := os.Create(filename)
if err != nil {
log.Printf("Failed to create profile file %s: %v\n", filename, err)
continue
}
if err := profile.Profile.Write(f); err != nil {
log.Printf("Failed to write profile %s: %v\n", filename, err)
}
f.Close()
log.Printf("Saved profile for %s (PID %d) to %s\n", profile.Command, profile.PID, filename)
}
}
Test OOMProf with the included test binaries:
# Run tests with different memory limits
sudo go test -v ./oomprof -run TestOOMProf
# Test with specific memory constraints
sudo go test -v ./oomprof -run TestOOMProfLowMemoryLimits
GODEBUG=memprofilerate=1 - Enable detailed memory profiling (set automatically by test programs)┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Go Process │ │ eBPF │ │ OOMProf │
│ │ │ │ │ │
│ ┌─────────────┐ │ │ ┌──────────────┐ │ │ ┌─────────────┐ │
│ │ Memory │ │ │ │ oom/mark_ │ │ │ │ Process │ │
│ │ Allocations │ │────┼▶│ victim │ │────┼▶│ Scanner │ │
│ │ │ │ │ │ signal/ │ │ │ │ │ │
│ └─────────────┘ │ │ │ signal_ │ │ │ └─────────────┘ │
│ │ │ │ deliver │ │ │ │
│ ┌─────────────┐ │ │ └──────────────┘ │ │ ┌─────────────┐ │
│ │ runtime. │ │ │ ┌──────────────┐ │ │ │ Profile │ │
│ │ mbuckets │ │◀───┼─┤ record_ │ ├────┼▶│ Generator │ │
│ └─────────────┘ │ │ │ profile_ │ │ │ └─────────────┘ │
│ │ │ │ buckets │ │ │ │
└─────────────────┘ │ └──────────────┘ │ └─────────────────┘
└──────────────────┘
# Generate eBPF objects and build binaries
make
# Run tests (requires root)
sudo go test -v ./oomprof
# Run specific test with memory limits
sudo go test -v ./oomprof -run TestOOMProfLowMemoryLimits
oomprof/
├── main.go # CLI interface
├── oomprof.c # eBPF programs (kernel space)
├── oomprof/
│ ├── monitor.go # Main monitoring logic
│ ├── pprof.go # Profile generation
│ └── oomprof_test.go # Test suite
├── tests/
│ ├── oomer/ # Memory allocation test scenarios
│ ├── gccache/ # GC cache stress test program
│ └── compile-oom/ # Go compiler stress test program
└── include/ # eBPF headers
Contributions are welcome! Please see the development section for build instructions and testing guidelines.
This project is licensed under the Apache License 2.0. See LICENSE for details.
213 followers · starred Aug 2025
767 followers · starred Sep 2025
191 followers · starred Aug 2025
293 followers · starred Aug 2025
OOMProf is an eBPF-based process monitor that automatically captures heap profiles from Go programs just before they are killed by the Linux Out-of-Memory (OOM) killer, or on-demand for specific processes. This enables post-mortem analysis of memory usage patterns that led to OOM conditions.
-p flagOOMProf uses eBPF tracepoints to monitor kernel OOM killer events and automatically:
oom/mark_victim tracepointsignal/signal_deliver tracepointThe captured profiles show memory allocation patterns, call stacks, and heap usage that can help identify memory leaks, excessive allocations, or other issues that led to the OOM condition.
# Clone the repository
git clone https://github.com/parca-dev/oomprof.git
cd oomprof
# Build the binaries
make
This creates:
oompa - Main OOMProf monitor (OOM Profiler Agent)tests/oomer.taux - Test binary for generating OOM conditionstests/gccache.taux - Test binary for GC cache stress testingoomprof.test - Test suiteRun OOMProf as root to monitor all Go processes:
sudo ./oompa
When a Go process is OOM killed, oompa will automatically generate a profile file named {command}-{pid}.pb.gz.
Profile specific processes by PID using the -p flag with comma-delimited PIDs:
# Profile a single process
sudo ./oompa -p 1234
# Profile multiple processes
sudo ./oompa -p 1234,5678,9012
This will generate profile files for each specified PID and exit once profiling is complete.
View the captured profile using Go's pprof tool:
# Interactive analysis
go tool pprof {command}-{pid}.pb.gz
# Generate a web interface
go tool pprof -http=:8080 {command}-{pid}.pb.gz
# View top memory consumers
go tool pprof -top {command}-{pid}.pb.gz
OOMProf can be used as a library in your own applications:
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/parca-dev/oomprof/oomprof"
)
func main() {
profileChan := make(chan oomprof.ProfileData)
state, err := oomprof.Setup(context.Background(), &oomprof.Config{}, profileChan)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to setup OOM profiler: %v\n", err)
os.Exit(1)
}
defer state.Close()
for profile := range profileChan {
// Create filename with timestamp: command-pid-YYYYMMDDHHmmss.pb.gz
timestamp := time.Now().Format("20060102150405")
filename := fmt.Sprintf("%s-%d-%s.pb.gz", profile.Command, profile.PID, timestamp)
f, err := os.Create(filename)
if err != nil {
log.Printf("Failed to create profile file %s: %v\n", filename, err)
continue
}
if err := profile.Profile.Write(f); err != nil {
log.Printf("Failed to write profile %s: %v\n", filename, err)
}
f.Close()
log.Printf("Saved profile for %s (PID %d) to %s\n", profile.Command, profile.PID, filename)
}
}
Test OOMProf with the included test binaries:
# Run tests with different memory limits
sudo go test -v ./oomprof -run TestOOMProf
# Test with specific memory constraints
sudo go test -v ./oomprof -run TestOOMProfLowMemoryLimits
GODEBUG=memprofilerate=1 - Enable detailed memory profiling (set automatically by test programs)┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Go Process │ │ eBPF │ │ OOMProf │
│ │ │ │ │ │
│ ┌─────────────┐ │ │ ┌──────────────┐ │ │ ┌─────────────┐ │
│ │ Memory │ │ │ │ oom/mark_ │ │ │ │ Process │ │
│ │ Allocations │ │────┼▶│ victim │ │────┼▶│ Scanner │ │
│ │ │ │ │ │ signal/ │ │ │ │ │ │
│ └─────────────┘ │ │ │ signal_ │ │ │ └─────────────┘ │
│ │ │ │ deliver │ │ │ │
│ ┌─────────────┐ │ │ └──────────────┘ │ │ ┌─────────────┐ │
│ │ runtime. │ │ │ ┌──────────────┐ │ │ │ Profile │ │
│ │ mbuckets │ │◀───┼─┤ record_ │ ├────┼▶│ Generator │ │
│ └─────────────┘ │ │ │ profile_ │ │ │ └─────────────┘ │
│ │ │ │ buckets │ │ │ │
└─────────────────┘ │ └──────────────┘ │ └─────────────────┘
└──────────────────┘
# Generate eBPF objects and build binaries
make
# Run tests (requires root)
sudo go test -v ./oomprof
# Run specific test with memory limits
sudo go test -v ./oomprof -run TestOOMProfLowMemoryLimits
oomprof/
├── main.go # CLI interface
├── oomprof.c # eBPF programs (kernel space)
├── oomprof/
│ ├── monitor.go # Main monitoring logic
│ ├── pprof.go # Profile generation
│ └── oomprof_test.go # Test suite
├── tests/
│ ├── oomer/ # Memory allocation test scenarios
│ ├── gccache/ # GC cache stress test program
│ └── compile-oom/ # Go compiler stress test program
└── include/ # eBPF headers
Contributions are welcome! Please see the development section for build instructions and testing guidelines.
This project is licensed under the Apache License 2.0. See LICENSE for details.
213 followers · starred Aug 2025
767 followers · starred Sep 2025
191 followers · starred Aug 2025
293 followers · starred Aug 2025