서문
OpenClaw는 Node.js 기반으로 실행되며, 기본적으로 V8 엔진의 힙 메모리 상한은 약 1.5GB(64비트 시스템)입니다. OpenClaw 프로세스의 메모리가 지속적으로 증가하여 시스템이 느려지거나 OOM(Out of Memory)으로 종료되는 경우, 본 글의 해결 방법을 통해 원인을 찾고 문제를 해결할 수 있습니다.
1. 메모리 상태 빠른 확인
1.1 현재 메모리 사용량 확인
# 방법 1: OpenClaw 헬스 엔드포인트를 통해 확인
curl -s http://localhost:18789/health/detail | jq '.memory'
# 응답 예시:
# {
# "heapUsed": "185MB",
# "heapTotal": "256MB",
# "rss": "310MB",
# "external": "12MB"
# }
# 방법 2: 프로세스 메모리 직접 확인
ps aux | grep openclaw | grep -v grep
# 방법 3: top/htop으로 실시간 확인
top -p $(pgrep -f "openclaw up")
1.2 메모리 지표 의미
| 지표 | 의미 | 정상 범위 |
|---|---|---|
| RSS | 실제 물리 메모리 사용량 | < 500MB |
| Heap Used | V8 힙 사용량 | < 300MB |
| Heap Total | V8 힙 총 할당량 | < 512MB |
| External | C++ 객체 메모리 | < 50MB |
Heap Used가 지속적으로 증가하면서 감소하지 않는다면 메모리 누수가 있을 가능성이 높습니다.
2. Node.js 메모리 제한 설정
2.1 최대 힙 메모리 설정
# 방법 1: 환경 변수로 설정
export NODE_OPTIONS="--max-old-space-size=512"
openclaw restart
# 방법 2: 설정 파일에서 설정 (PM2 방식)
# ecosystem.config.js
{
env: {
NODE_OPTIONS: "--max-old-space-size=512"
}
}
# 방법 3: Systemd 방식
# /etc/systemd/system/openclaw.service
# Environment=NODE_OPTIONS=--max-old-space-size=512
권장 메모리 제한 설정:
| 서버 메모리 | 권장 max-old-space-size | 설명 |
|---|---|---|
| 512MB | 256 | 저사양 VPS, 최소 설정 필요 |
| 1GB | 384 | 입문 수준, 2-3개 채널 지원 |
| 2GB | 512 | 표준 설정 |
| 4GB+ | 1024 | 충분, 다채널 고동시성에 적합 |
2.2 가비지 컬렉션 최적화 활성화
# GC를 노출하여 수동 트리거 허용
export NODE_OPTIONS="--max-old-space-size=512 --expose-gc"
# 더 적극적인 GC 전략 (메모리를 줄이지만 성능에 약간 영향)
export NODE_OPTIONS="--max-old-space-size=512 --gc-interval=100"
3. 대화 기록 정리
대화 기록은 메모리 증가의 주요 원인 중 하나입니다. 각 활성 대화마다 메모리에 컨텍스트가 유지됩니다.
3.1 대화 컨텍스트 제한 설정
// ~/.config/openclaw/openclaw.json5
{
"conversation": {
// 대화당 유지하는 최대 메시지 수
"maxMessages": 50,
// 대화 유휴 타임아웃(초), 타임아웃 후 메모리 정리
"idleTimeout": 1800,
// 최대 동시 대화 수
"maxConcurrent": 100,
// 컨텍스트 윈도우 전략: sliding(슬라이딩 윈도우) 또는 summarize(요약)
"contextStrategy": "sliding"
}
}
3.2 대화 캐시 수동 정리
# API를 통해 비활성 대화 모두 정리
curl -X POST http://localhost:18789/admin/cleanup \
-H "Content-Type: application/json" \
-d '{"type": "conversations", "olderThan": "1h"}'
# 서비스 재시작 (메모리의 모든 대화가 지워짐)
openclaw restart
3.3 정기 자동 정리
# 정기 정리 스크립트 생성
cat > /usr/local/bin/openclaw-cleanup.sh << 'EOF'
#!/bin/bash
curl -sf -X POST http://localhost:18789/admin/cleanup \
-H "Content-Type: application/json" \
-d '{"type": "conversations", "olderThan": "2h"}'
echo "[$(date)] 대화 캐시 정리 완료" >> /var/log/openclaw-cleanup.log
EOF
chmod +x /usr/local/bin/openclaw-cleanup.sh
# 매시간 실행
echo "0 * * * * /usr/local/bin/openclaw-cleanup.sh" | crontab -
4. 메모리 누수 감지
4.1 Node.js 내장 진단 사용
# 시작 시 힙 스냅샷 기능 활성화
export NODE_OPTIONS="--max-old-space-size=512 --heapsnapshot-signal=SIGUSR2"
openclaw restart
# 메모리 증가 시 힙 스냅샷 생성
kill -USR2 $(pgrep -f "openclaw up")
# 스냅샷 파일이 작업 디렉토리에 생성됩니다. Chrome DevTools로 분석할 수 있습니다
# Chrome 열기 -> F12 -> Memory -> 스냅샷 파일 로드
4.2 메모리 증가 추이 모니터링
#!/bin/bash
# memory-monitor.sh로 저장
# 매분 메모리 사용량을 기록하여 추이 분석에 활용
LOG_FILE="/var/log/openclaw-memory.csv"
# 헤더 작성
if [ ! -f "$LOG_FILE" ]; then
echo "timestamp,rss_kb,heap_used,heap_total" > "$LOG_FILE"
fi
while true; do
TIMESTAMP=$(date +%Y-%m-%dT%H:%M:%S)
RSS=$(ps -o rss= -p $(pgrep -f "openclaw up") 2>/dev/null)
HEALTH=$(curl -sf http://localhost:18789/health/detail 2>/dev/null)
if [ -n "$RSS" ] && [ -n "$HEALTH" ]; then
HEAP_USED=$(echo "$HEALTH" | jq -r '.memory.heapUsed')
HEAP_TOTAL=$(echo "$HEALTH" | jq -r '.memory.heapTotal')
echo "$TIMESTAMP,$RSS,$HEAP_USED,$HEAP_TOTAL" >> "$LOG_FILE"
fi
sleep 60
done
4.3 메모리 누수의 특징 식별
위의 로그를 분석하여 메모리 누수 여부를 판단합니다:
- 정상적인 동작: GC 이후 메모리가 안정적인 수준으로 복귀하며 톱니 형태로 변동
- 메모리 누수: 메모리가 지속적으로 상승하며 GC 이후의 기준선도 계속 높아짐
- 일회성 증가: 대량의 스킬을 로드하거나 여러 채널에 연결할 때 한 번에 증가한 후 안정화
5. 힙 스냅샷 분석
5.1 힙 스냅샷 생성
# 방법 1: 시그널을 통한 트리거
kill -USR2 $(pgrep -f "openclaw up")
# 스냅샷 파일이 현재 작업 디렉토리에 생성됨
# 방법 2: v8-profiler 사용 (코드 레벨 지원 필요)
# 보통 개발 디버깅 시 사용
5.2 Chrome DevTools를 이용한 분석
- Chrome 브라우저 열기
- 주소창에
chrome://inspect입력 - "Open dedicated DevTools for Node" 클릭
- Memory 탭으로 전환
.heapsnapshot파일 로드- "Retained Size" 기준으로 정렬하여 가장 많은 메모리를 차지하는 객체 찾기
5.3 일반적인 메모리 누수 원인
| 누수 원인 | 증상 | 해결 방법 |
|---|---|---|
| 정리되지 않은 이벤트 리스너 | EventEmitter 객체 증가 | removeListener 확인 |
| 상한 없는 전역 캐시 | Map/Object 지속 증가 | 캐시 상한 및 LRU 전략 설정 |
| 닫히지 않은 WebSocket | Socket 객체 축적 | 연결 해제 정리 로직 확인 |
| 대규모 대화 컨텍스트 | String 객체 과다 사용 | 컨텍스트 길이 제한 |
| 스킬 플러그인 누수 | 서드파티 코드 문제 | 하나씩 비활성화하며 확인 |
6. 저메모리 장치 최적화
라즈베리 파이, 저사양 VPS 등 메모리가 제한된 장치에서 OpenClaw를 실행하는 경우 다음 설정으로 메모리 사용량을 대폭 줄일 수 있습니다.
6.1 최소 설정
// ~/.config/openclaw/openclaw.json5 - 저메모리 최적화 버전
{
"conversation": {
"maxMessages": 20,
"idleTimeout": 600,
"maxConcurrent": 20,
"contextStrategy": "sliding"
},
"skills": {
// 필수 스킬만 로드
"autoLoad": false,
"whitelist": ["basic-chat"]
},
"channels": {
// 필수 채널만 활성화
},
"cache": {
"maxSize": "50MB"
}
}
6.2 Swap을 버퍼로 사용
# 1GB swap 파일 생성
sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 영구 적용
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
# swappiness 조정 (10으로 낮춰 물리 메모리 우선 사용)
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
6.3 경량 모델 사용
더 작은 모델을 선택하면 컨텍스트 처리의 메모리 오버헤드를 줄일 수 있습니다:
{
"models": {
"primary": {
"provider": "ollama",
"model": "phi3:mini" // 약 2GB VRAM/메모리
}
}
}
7. PM2 메모리 제한 자동 재시작
PM2의 메모리 제한 기능을 활용하여 메모리 초과 시 자동으로 재시작합니다:
// ecosystem.config.js
module.exports = {
apps: [{
name: "openclaw",
script: "openclaw",
args: "up",
max_memory_restart: "400M",
env: {
NODE_OPTIONS: "--max-old-space-size=512"
}
}]
};
# 설정 적용
pm2 start ecosystem.config.js
# 메모리 사용량 및 재시작 횟수 확인
pm2 describe openclaw | grep -E "memory|restart"
8. 메모리 문제 해결 흐름도
메모리 과다
│
├── RSS > 500MB?
│ ├── 예 → Heap Used 확인
│ │ ├── Heap Used 지속 증가 → 메모리 누수
│ │ │ ├── 힙 스냅샷 생성 및 분석
│ │ │ ├── 스킬 하나씩 비활성화하며 확인
│ │ │ └── 대화 컨텍스트 제한 확인
│ │ └── Heap Used 안정적 → External 메모리
│ │ └── MCP Server 또는 네이티브 모듈 확인
│ └── 아니오 → 정상 범위
│
└── OOM Killer에 의해 종료?
├── swap 공간 추가
├── --max-old-space-size 설정
├── 동시 대화 수 줄이기
└── 서버 메모리 업그레이드
위의 방법을 통해 대부분의 OpenClaw 메모리 관련 문제를 진단하고 해결할 수 있습니다. 메모리 누수가 지속된다면 OpenClaw의 GitHub 저장소에 Issue를 제출하고 힙 스냅샷 분석 결과를 첨부하는 것을 권장합니다.