Oracle ORA-04031 오류 원인과 해결 방법 완벽 가이드

ORA-04031
2026년 08월 20일 | DBMS Error 가이드

이 글에서 다루는 내용

ORA-04031 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

ORA-04031 unable to allocate bytes of shared memory 는?

ORA-04031은 Oracle 데이터베이스의 Shared Pool, Large Pool, Java Pool, Streams Pool 등 SGA(System Global Area) 내의 공유 메모리 영역에서 요청한 크기의 연속된 메모리 공간을 할당할 수 없을 때 발생하는 에러입니다. 이 에러는 SGA 영역이 단순히 부족한 경우뿐만 아니라, 메모리 단편화(Fragmentation)로 인해 물리적 공간은 존재하지만 연속된 공간이 부족할 때도 발생합니다. 특히 OLTP 환경에서 수많은 하드 파싱(Hard Parsing)이 반복되거나, 대형 패키지/프로시저가 로딩될 때 자주 발생하며, 방치할 경우 애플리케이션 전체가 응답 불가 상태에 빠질 수 있어 즉각적인 조치가 필요한 심각한 에러입니다.


주요 발생 원인

  • Shared Pool 크기 부족 및 메모리 단편화

Shared Pool은 SQL 커서, 실행 계획, 딕셔너리 캐시 등을 저장하는 핵심 SGA 영역으로, 이 공간이 절대적으로 부족하거나 오랜 운영으로 인해 단편화가 심화되면 ORA-04031이 발생합니다. 특히 바인드 변수를 사용하지 않는 리터럴 SQL이 대량으로 유입될 경우, 유사한 SQL이 각각 다른 커서로 파싱되어 Shared Pool을 빠르게 잠식합니다. 또한 Free Memory가 존재하더라도 연속된 청크(Chunk)가 없으면 에러가 발생하는 점이 이 에러를 더욱 까다롭게 만듭니다.

  • 바인드 변수 미사용으로 인한 하드 파싱 폭증

바인드 변수를 사용하지 않고 리터럴 값을 SQL에 직접 삽입하면, 의미상 동일한 SQL임에도 불구하고 Oracle은 각각 별개의 SQL로 인식하여 매번 하드 파싱을 수행합니다. 이로 인해 Shared Pool 내 Library Cache에 수만 개의 중복 커서가 쌓이게 되어 메모리가 빠르게 소진됩니다. 이는 ORA-04031의 가장 흔한 원인 중 하나이며, 개발 단계에서부터 바인드 변수 사용을 강제하는 것이 근본적인 해결책입니다.

  • CURSOR_SHARING 파라미터 미설정 및 대형 오브젝트 로딩

CURSOR_SHARING 파라미터가 EXACT(기본값)로 설정된 환경에서 리터럴 SQL이 다수 실행되면, 바인드 변수 문제와 결합되어 메모리 고갈을 가속화합니다. 또한 수백 MB에 달하는 대형 PL/SQL 패키지, Java 클래스, 또는 대용량 XML 파서 등이 메모리에 로드될 때, 연속된 대용량 청크를 확보하지 못하면 에러가 발생합니다. JAVA_POOL_SIZELARGE_POOL_SIZE가 너무 작게 설정된 경우도 이 범주에 해당합니다.


해결 방법

1단계: 현재 Shared Pool 상태 진단

먼저 Shared Pool의 실제 사용 현황과 단편화 정도를 파악합니다.

-- Shared Pool 여유 공간 확인
SELECT pool, name, bytes / 1024 / 1024 AS mb_free
FROM v$sgastat
WHERE pool = 'shared pool'
  AND name = 'free memory';

-- Shared Pool 전체 구성 요소 확인
SELECT pool, name, bytes / 1024 / 1024 AS mb
FROM v$sgastat
WHERE pool = 'shared pool'
ORDER BY bytes DESC
FETCH FIRST 20 ROWS ONLY;

-- 메모리 단편화 수준 확인 (청크 크기 분포)
SELECT ksmchcls AS class,
       COUNT(*)  AS chunks,
       SUM(ksmchsiz) / 1024 / 1024 AS total_mb,
       MAX(ksmchsiz) / 1024 AS max_chunk_kb,
       MIN(ksmchsiz)        AS min_chunk_bytes
FROM x$ksmsp
GROUP BY ksmchcls
ORDER BY total_mb DESC;

2단계: 바인드 변수 미사용 SQL 식별

-- 리터럴 SQL 다발 식별 (유사 SQL 그루핑)
SELECT SUBSTR(sql_text, 1, 60) AS sql_snippet,
       COUNT(*) AS cnt,
       SUM(sharable_mem) / 1024 / 1024 AS total_mem_mb
FROM v$sql
GROUP BY SUBSTR(sql_text, 1, 60)
HAVING COUNT(*) > 10
ORDER BY cnt DESC
FETCH FIRST 20 ROWS ONLY;

-- 하드 파싱 비율 확인
SELECT name, value
FROM v$sysstat
WHERE name IN (
    'parse count (total)',
    'parse count (hard)',
    'parse count (failures)'
)
ORDER BY name;

3단계: Shared Pool 즉각 조치 (Flush)

> ⚠️ 주의: 운영 환경에서 ALTER SYSTEM FLUSH SHARED_POOL은 일시적인 성능 저하를 유발할 수 있으므로, 반드시 비업무 시간대에 수행하거나 DBA의 판단하에 실행하세요.

-- Shared Pool Flush (단편화 해소 목적, 임시방편)
ALTER SYSTEM FLUSH SHARED_POOL;

-- Shared Pool 크기 동적 증가 (SGA_MAX_SIZE 범위 내에서)
ALTER SYSTEM SET SHARED_POOL_SIZE = 2G SCOPE = BOTH;

-- Large Pool 크기 조정 (병렬 쿼리, RMAN 사용 환경)
ALTER SYSTEM SET LARGE_POOL_SIZE = 512M SCOPE = BOTH;

-- Java Pool 크기 조정 (Java 사용 환경)
ALTER SYSTEM SET JAVA_POOL_SIZE = 256M SCOPE = BOTH;

4단계: CURSOR_SHARING 파라미터 임시 조정

-- 세션 레벨에서 CURSOR_SHARING 조정 (테스트 후 적용)
ALTER SESSION SET CURSOR_SHARING = FORCE;

-- 시스템 레벨 적용 (주의: 기존 실행 계획에 영향 가능)
ALTER SYSTEM SET CURSOR_SHARING = FORCE SCOPE = BOTH;

-- 적용 전 현재 설정 확인
SHOW PARAMETER CURSOR_SHARING;

5단계: AMM/ASMM 활성화 검토 (11g 이상)

-- 현재 메모리 관리 방식 확인
SHOW PARAMETER memory_target;
SHOW PARAMETER sga_target;

-- ASMM(Automatic Shared Memory Management) 활성화
ALTER SYSTEM SET SGA_TARGET = 4G SCOPE = SPFILE;
ALTER SYSTEM SET MEMORY_TARGET = 0 SCOPE = SPFILE;  -- AMM 비활성화 시
-- ※ 변경 후 DB 재시작 필요 (SPFILE 사용 시)

-- Shared Pool Reserved Size 설정 (대형 오브젝트 로딩용)
ALTER SYSTEM SET SHARED_POOL_RESERVED_SIZE = 200M SCOPE = SPFILE;

6단계: 캐시에 고정시킬 오브젝트 설정 (Pin)

-- 자주 사용하는 패키지를 Shared Pool에 고정 (Pinning)
EXECUTE DBMS_SHARED_POOL.KEEP('SYS.STANDARD', 'P');
EXECUTE DBMS_SHARED_POOL.KEEP('HR.MY_LARGE_PACKAGE', 'P');

-- 현재 KEEP 처리된 오브젝트 확인
SELECT owner, name, type, kept
FROM v$db_object_cache
WHERE kept = 'YES'
ORDER BY owner, name;

예방 방법

  • 정기적인 SGA 모니터링 및 AWR/ASH 분석 자동화

ORA-04031은 대부분 서서히 진행되다가 임계점에서 폭발적으로 발생합니다. AWR(Automatic Workload Repository) 리포트를 주기적으로 분석하여 “Shared Pool” 섹션의 메모리 고갈 추이를 사전에 파악하고, OEM(Oracle Enterprise Manager) 또는 커스텀 스크립트를 통해 v$sgastat의 free memory가 전체 Shared Pool의 10% 이하로 떨어질 경우 즉시 알람이 발송되도록 임계값을 설정해두는 것이 필수입니다.

“`sql

— AWR 기반 Shared Pool 메모리 추이 조회 (최근 7일)

SELECT s.snap_id,

TO_CHAR(s.begin_interval_time, ‘YYYY-MM-DD HH24:MI’) AS snap_time,

p.value / 1024 / 1024 AS shared_pool_mb

FROM dba_hist_snapshot s

JOIN dba_hist_parameter p

ON s.snap_id = p.snap_id

AND s.dbid = p.dbid

WHERE p.parameter_name = ‘shared_pool_size’

AND s.begin_interval_time >= SYSDATE – 7

ORDER BY s.snap_id;

“`

  • 개발 표준에 바인드 변수 사용 의무화 및 코드 리뷰 프로세스 도입

애플리케이션 개발 단계에서부터 바인드 변수 사용을 필수 코딩 표준으로 지정하고, 코드 리뷰 단계에서 리터럴 SQL을 자동으로 감지하는 정적 분석 도구를 도입해야 합니다. 운영 환경에서는 V$SQL을 주기적으로 조회하여 PARSE_CALLSEXECUTIONS에 근접하는 SQL(하드 파싱 비율이 높은 SQL)을 식별하고, 해당 개발팀에 리팩토링을 요청하는 프로세스를 정례화하는 것이 장기적인 안정성의 핵심입니다.


관련 에러

  • ORA-04030: out of process memory when trying to allocate bytes — OS 프로세스 레벨의 PGA 메모리 부족 시 발생하며, ORA-04031이 SGA 문제라면 ORA-04030은 PGA/OS 메모리 문제입니다. 두 에러가 동시에 발생한다면 서버 전체 메모리 용량을 즉시 점검해야 합니다.
  • ORA-04032: pga_aggregate_target too small — PGA 메모리 관련 에러로, 정렬/해시 연산에 필요한 PGA가 부족할 때 발생합니다.
  • ORA-02097: parameter cannot be modified because specified value is invalid — Shared Pool 파라미터 변경 시 유효하지 않은 값을 지정했을 때 발생하는 보조 에러입니다.
  • ORA-00604: error occurred at recursive SQL level — ORA-04031이 내부 재귀 SQL 실행 중에 발생할 경우 함께 나타나는 에러입니다.

DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기