본문 바로가기
IT

ORA-04031 unable to allocate shared memory — 공유 메모리 부족 에러 원인·해결·예방 완전 정리

by 샤나엘 2026. 5. 24.
반응형

ORA-04031 unable to allocate shared memory — 공유 메모리 부족 에러 원인·해결·예방 완전 정리

Oracle 데이터베이스를 장시간 운영하다 보면 어느 순간 ORA-04031: unable to allocate N bytes of shared memory가 갑작스럽게 터지는 경우가 있다. SGA 안의 Shared Pool·Large Pool·Java Pool에서 연속된 메모리 청크를 확보하지 못해 발생하는 에러로, 단순히 "메모리가 모자란" 상태만이 아니라 단편화(fragmentation) 가 핵심 원인인 경우가 많다.

 

본 글은 ORA-04031의 정확한 의미, 7가지 발생 원인, 진단 SQL과 즉시 조치 명령, 바인드 변수·ASMM·Reserved Pool을 활용한 해결법, 그리고 운영 환경에서 재발을 막기 위한 예방 전략까지 정리한다.

 

ORA-04031

이 글의 구성

 

01에러 메시지와 ORA-04031의 의미
02발생 원인 7가지
03진단 SQL과 즉시 조치
04해결 방법과 메모리 관리 옵션
05예방 전략과 운영 체크리스트
06인접 메모리 에러와의 차이
Q&A자주 묻는 질문 5가지

01 에러 메시지와 ORA-04031의 의미

항목 내용
에러 코드 ORA-04031
메시지 형식 unable to allocate %s bytes of shared memory ("pool","object","heap","chunk")
의미 SGA 안의 지정된 풀에서 요청 크기의 연속 청크를 확보하지 못한 상태
발생 영역 Shared Pool · Large Pool · Java Pool · Streams Pool
핵심 원인 절대 용량 부족 또는 단편화(fragmentation)
참고 문서 MOS Doc ID 396940.1 · 146599.1 · 1088239.1

ORA-04031 메시지는 4개의 인자를 함께 노출한다. 가장 흔히 보이는 ("shared pool","sql area","kglsim heap") 같은 형태가 그 예시다. 첫 번째 인자는 요청한 바이트, 두 번째는 영역명, 세 번째는 컴포넌트, 네 번째는 청크명으로 사실상 어느 풀이 어떤 용도로 메모리를 요구했는지 알려준다.

핵심 관찰 — 빈 메모리가 있어도 발생할 수 있다

ORA-04031은 단순히 free memory가 0일 때만 발생하지 않는다. V$SGASTAT에 free memory가 수백 MB 남아 있어도, 그 메모리가 잘게 쪼개져 있어 요청한 연속 청크를 확보하지 못하면 똑같이 발생한다. 이 때문에 단편화 진단이 절대 용량 점검만큼 중요하다.


02 발생 원인 7가지

원인 1 — Shared Pool 절대 용량 부족

SQL Area, Library Cache, Row Cache, PL/SQL 객체가 누적되면서 Shared Pool에 빈 메모리 자체가 부족해진 상태다. SGA_TARGET 또는 SHARED_POOL_SIZE가 워크로드 대비 작게 잡혔을 때 발생한다.

원인 2 — 하드 파싱 과다(가장 흔한 근본 원인)

애플리케이션이 바인드 변수를 쓰지 않고 값을 SQL 문자열에 그대로 박아 넣으면, 값만 바뀐 SQL 수만 건이 매번 새 커서로 등록되어 Shared Pool을 빠르게 채우고 단편화시킨다. WHERE 조건의 ID 값마다 새 커서가 만들어지는 패턴이 대표적이다.

원인 3 — 메모리 단편화

장기 운영 인스턴스에서 작은 청크 할당·해제가 반복되면 free 메모리가 자잘하게 쪼개진다. 합산 free 공간은 충분해 보여도 4KB 이상의 연속 청크 요청이 실패한다. V$SHARED_POOL_RESERVED의 max_free_size와 request_failures가 핵심 지표다.

원인 4 — 대형 PL/SQL 객체 reload

대형 패키지·트리거·뷰가 무효화된 뒤 재컴파일되면서 큰 연속 청크를 요구하는 케이스다. Reserved Pool이 충분치 않으면 ORA-04031이 그 객체 reload 시점에 정확히 재현된다.

원인 5 — Java Pool · Streams Pool 부족

Oracle JVM(UTL_HTTP·Spatial 일부)·GoldenGate·AQ를 적극적으로 사용하는 환경에서 Java Pool 또는 Streams Pool의 크기가 모자라 발생한다. 메시지의 두 번째 인자가 "java pool" 또는 "streams pool"로 표시된다.

원인 6 — Reserved Pool 미설정 또는 과소

SHARED_POOL_RESERVED_SIZE는 4400바이트(_SHARED_POOL_RESERVED_MIN_ALLOC) 이상의 큰 청크 요구를 받아내는 전용 영역이다. 이 값이 너무 작으면 큰 청크 요청에서 즉시 단편화 영향을 받는다.

원인 7 — 알려진 버그·메모리 누수

19c RU 미적용 환경의 Library Cache 누수, KGH heap 누수 등 다수의 버그가 ORA-04031로 표면화된다. 같은 컴포넌트(예: kgh: no access)가 반복 등장하면 패치 점검 대상이다. MOS에서 두 번째·세 번째 인자로 검색하면 일치하는 Doc ID를 찾을 수 있다.


03 진단 SQL과 즉시 조치

SGA 영역별 free 메모리 확인

SELECT pool, name, bytes/1024/1024 AS mb
FROM   v$sgastat
WHERE  name = 'free memory'
ORDER BY pool;

Reserved Pool 단편화 핵심 지표

SELECT free_space, avg_free_size, free_count,
       max_free_size, used_space,
       request_failures, last_failure_size
FROM   v$shared_pool_reserved;

request_failures가 0이 아니거나 max_free_size가 작은 값으로 떨어졌다면 Reserved Pool 단편화가 강하게 의심된다.

메모리 점유 TOP SQL과 하드 파싱 비율

-- 메모리 점유 TOP 20 커서
SELECT sql_id, executions, sharable_mem, version_count,
       SUBSTR(sql_text, 1, 80) AS sql_short
FROM   v$sql
ORDER BY sharable_mem DESC
FETCH FIRST 20 ROWS ONLY;

-- 하드 파싱 비율(10% 초과 시 위험 신호)
SELECT name, value
FROM   v$sysstat
WHERE  name IN ('parse count (total)',
                'parse count (hard)');

즉시 조치 — Shared Pool flush(운영 중 신중하게)

-- 단편화 임시 해소(직후 하드 파싱 폭증 주의)
ALTER SYSTEM FLUSH SHARED_POOL;

-- 특정 커서만 제거(권장)
EXEC DBMS_SHARED_POOL.PURGE('address,hash_value', 'C');

FLUSH SHARED_POOL은 모든 캐시된 커서를 무효화하므로, 직후 하드 파싱이 일제히 일어나며 일시적 성능 저하가 따라온다. 가능하면 문제 커서만 DBMS_SHARED_POOL.PURGE로 제거하는 것이 안전하다.


04 해결 방법과 메모리 관리 옵션

단기 — Shared Pool / Reserved Pool 상향

-- SGA / Shared Pool 자체 상향
ALTER SYSTEM SET sga_target=8G SCOPE=BOTH;
ALTER SYSTEM SET shared_pool_size=2G SCOPE=BOTH;

-- Reserved Pool은 Shared Pool의 약 10%를 권장
ALTER SYSTEM SET shared_pool_reserved_size=200M
                  SCOPE=SPFILE;

중장기 — 바인드 변수와 CURSOR_SHARING

근본 원인이 하드 파싱 과다라면 메모리만 늘려도 시간만 벌 뿐이다. 애플리케이션 단에서 바인드 변수를 사용하도록 코드를 고치는 것이 가장 안전한 해결책이다. JDBC라면 PreparedStatement, .NET이라면 파라미터 컬렉션, ORM이라면 named parameter를 사용한다.

당장 코드 수정이 어렵다면 CURSOR_SHARING 파라미터를 일시적으로 활용한다.

-- 리터럴을 시스템이 자동으로 바인드로 치환
ALTER SYSTEM SET cursor_sharing=FORCE
                  SCOPE=BOTH;

FORCE는 효과가 크지만 실행계획 안정성에 부작용을 줄 수 있어 영구 옵션보다는 상황 대응용으로 본다. EXACT(기본)로 돌리는 것을 전제로 코드 개선이 이상적이다.

ASMM과 AMM

SGA_TARGET만 잡고 개별 풀은 비워 두면 ASMM(Automatic Shared Memory Management)이 동작하면서 워크로드에 맞춰 풀 크기를 자동 조정한다. MEMORY_TARGET까지 잡으면 AMM(Automatic Memory Management)이 되어 PGA까지 함께 자동 관리하지만, 19c 이후 Linux HugePages 환경에서는 AMM이 권장되지 않는다. Linux 운영 환경은 ASMM + HugePages 조합이 표준이다.

12c+ Multitenant 환경 주의점

CDB/PDB 구성에서는 한 PDB가 Shared Pool을 다 소진하면 같은 CDB의 다른 PDB까지 ORA-04031에 노출된다. 12.2부터 PDB별 SGA_TARGET, SGA_MIN_SIZE를 설정할 수 있고(19c·21c·23ai에서도 지원), 이를 통해 PDB 간 메모리 격리를 명시적으로 잡아 주는 것이 안전하다.


05 예방 전략과 운영 체크리스트

영역 권장 조치
애플리케이션 바인드 변수 강제, ORM의 in-clause padding 활성화, 동적 SQL 최소화
메모리 설정 ASMM(SGA_TARGET) + HugePages, Reserved Pool은 Shared Pool의 약 10%
대형 객체 DBMS_SHARED_POOL.KEEP으로 대형 패키지를 Reserved에 고정
모니터링 AWR Memory Advice 주간 점검, V$SHARED_POOL_RESERVED 추세 보존
패치 19c·21c·23ai 최신 RU 적용(Library Cache·KGH 누수 다수 수정)
운영 절차 야간 배치 후 V$SGASTAT 스냅샷, ORA-04031 알람 즉시 Pager

대형 PL/SQL 패키지는 미리 KEEP 처리해 두면 reload 시점에 큰 청크를 새로 요구하지 않아 ORA-04031 위험을 낮춘다.

-- 자주 무효화되는 대형 객체를 Reserved Pool에 고정
EXEC DBMS_SHARED_POOL.KEEP('APP_OWNER.LARGE_PKG', 'P');

06 인접 메모리 에러와의 차이

에러 코드 영역 / 원인 조치 방향
ORA-04031 SGA 풀 연속 청크 할당 실패 바인드 변수, SGA 상향, Reserved Pool 증설
ORA-04030 PGA(프로세스 사용 메모리) 부족 PGA_AGGREGATE_TARGET 증대, OS 메모리 점검
ORA-00020 PROCESSES 파라미터 한계 초과 PROCESSES 상향, 커넥션 풀 점검
ORA-01555 언두 세그먼트 재사용으로 일관성 실패 UNDO_RETENTION 조정, 장기 쿼리 분리
ORA-01652 TEMP 테이블스페이스 부족 Tempfile 추가, PGA 정렬 메모리 확보

ORA-04030은 같은 메모리 계열이지만 PGA(서버 프로세스 단위 메모리) 부족이고, ORA-04031은 SGA(공유 영역) 부족이라는 점에서 본질적으로 다르다. OS의 free 메모리가 충분한데도 ORA-04030이 보이면 MEMLOCK, cgroup, ulimit -v 등 OS 제약을 먼저 점검한다.


07 자주 묻는 질문

Q1. ORA-04031이 한 번만 발생했는데 SGA를 늘려야 하나요?

한 번이면 즉시 증설보다 원인 진단이 우선이다. 메시지의 두 번째·세 번째 인자를 메모해 두고 V$SHARED_POOL_RESERVED, V$SQL의 sharable_mem 추이를 확인한다. 단편화가 재발 패턴으로 보일 때만 SGA·Reserved Pool 증설을 검토한다.

Q2. FLUSH SHARED_POOL을 운영 시간에 해도 되나요?

기술적으로 가능하지만 직후 하드 파싱이 일제히 발생해 CPU 사용률과 응답 지연이 일시적으로 치솟는다. 가능하면 한가한 시간대에 수행하거나 DBMS_SHARED_POOL.PURGE로 문제 커서만 제거하는 편이 안전하다.

Q3. CURSOR_SHARING=FORCE는 영구 설정해도 되나요?

상황에 따라 다르다. 컬럼 통계가 왜곡된 리터럴(예: 특정 값 분포가 매우 편향된 경우)에서 실행계획이 비효율적으로 고정될 위험이 있다. 임시 처방으로 쓰고 가능한 한 애플리케이션 바인드 변수 적용으로 복귀하는 것을 권장한다.

Q4. 19c에서 AMM과 ASMM 중 무엇이 좋나요?

Linux 환경에서는 ASMM + HugePages 조합이 표준이다. AMM은 HugePages와 함께 쓰기 어렵고, RAC·고부하 환경에서 메모리 추적이 더 까다롭다. Windows 환경에서는 AMM도 무난하다.

Q5. ORA-04031 알람 자동화는 어떻게 하나요?

DBA_HIST_ALERT_HISTORY, 또는 alert.log를 파일 모니터링 도구로 tail해 정규식 ORA-04031이 잡히면 즉시 Pager로 전달한다. Enterprise Manager Cloud Control에서는 기본 메트릭으로 ORA-04031을 제공한다.


마무리

ORA-04031은 "메모리를 더 주면 된다"는 단순한 결론을 내리기 쉬운 에러지만, 실제 운영 현장에서는 하드 파싱 과다와 단편화가 본질인 경우가 대부분이다. 알람이 떴을 때 가장 먼저 확인할 항목은 메시지의 두 번째 인자(어느 풀에서 실패했는지)와 V$SHARED_POOL_RESERVED의 request_failures·max_free_size다.

 

장기 안정성을 원한다면 애플리케이션 바인드 변수 적용 → ASMM + HugePages 구성 → Reserved Pool 적정 비율 설정 → 최신 RU 적용의 4단계를 순서대로 챙기는 것이 정석이다. 단기 대응으로 FLUSH SHARED_POOL을 두 번 이상 사용하게 된다면 그것은 이미 구조적 개선이 필요하다는 신호다.

ORA-04031 트러블슈팅 체크리스트

 

01에러 메시지의 두 번째 인자로 실패한 풀(shared/large/java/streams) 식별.
02V$SGASTAT의 free memory와 V$SHARED_POOL_RESERVED 단편화 지표 동시 점검.
03하드 파싱 비율(parse count hard/total)이 10%를 초과하면 바인드 변수 적용 우선.
04SHARED_POOL_RESERVED_SIZE를 Shared Pool의 약 10%로 확보.
05Linux 환경에서는 ASMM(SGA_TARGET) + HugePages 조합을 표준으로 채택.
06FLUSH SHARED_POOL 대신 DBMS_SHARED_POOL.PURGE로 문제 커서만 제거.
0719c·21c·23ai 최신 RU 적용으로 Library Cache·KGH 누수 버그 차단.

본 글은 Oracle Database 공유 메모리 부족 에러 ORA-04031의 일반적 원인과 해결 방법을 정리한 자료다. 운영 환경 적용 전 테스트 환경에서 충분히 검증한다.

 

#ORA04031 #unableToAllocateSharedMemory #오라클에러 #SharedPool #LargePool #JavaPool #SGA단편화 #바인드변수 #하드파싱 #CURSOR_SHARING #ASMM #HugePages #ReservedPool #ORA04030 #ORA01555

반응형

댓글