【Oracle】ORA-04030の原因と解決方法|PGA不足・プロセスメモリ不足を切り分ける

【Oracle】ORA-04030の原因と解決方法|PGA不足・プロセスメモリ不足を切り分ける Oracle

ORA-04030: out of process memory は、Oracleのサーバープロセスやバックグラウンドプロセスが、処理に必要な私有メモリを確保できなかったときに発生するエラーです。共有プール不足を示す ORA-04031 と似ていますが、ORA-04030で主に見るべき場所は、PGA、OSメモリ、プロセスごとのメモリ上限、大量処理SQLやPL/SQLのメモリ使用量です。

対処は単純にメモリ設定を増やすだけではありません。どのプロセスが、どの種類のメモリを、どの処理で使い切ったのかを確認しないと、再発時に同じSQLやバッチがまた失敗します。この記事では、障害時に見る順番、確認SQL、よくある原因、設定変更前の注意点を実務寄りに整理します。

先に結論
ORA-04030は「Oracleプロセスの私有メモリ不足」です。まずアラートログとトレースで発生プロセスを確認し、v$process_memoryv$pgastatv$process、OS側のメモリ/上限を見ます。PGA設定だけでなく、巨大なBULK COLLECT、ソート、ハッシュ結合、並列実行、メモリリーク疑いも候補に入れます。
スポンサーリンク

ORA-04030とは

Oracle公式のエラー説明では、ORA-04030はプロセス私有メモリを確保できない、またはOSメモリやプロセス単位の上限に達した場合に発生するとされています。また、1つのOracleプロセスには内部的な上限があり、単一プロセスで極端に大きなメモリを使う場合はメモリリーク疑いも含めて調査対象になります。メッセージには、確保しようとしたバイト数と、どの領域で失敗したかを示す引数が出ることがあります。

代表的なメッセージは次のような形です。

ora-04030-message.txt
ORA-04030: out of process memory when trying to allocate 16328 bytes (koh-kghu sessi,pl/sql vc2)

koh-kghu sessipl/sql vc2 のような引数は、どの内部領域でメモリ確保に失敗したかを調べる手掛かりです。ただし、引数だけで断定せず、発生時刻、SQL、セッション、PGA使用量、OSメモリを合わせて確認します。Oracleのメモリ全体像は SGA・PGAメモリ管理完全ガイド も参考になります。

まず見る場所

アラートログとトレース

発生時刻、プロセスID、SQL ID、メモリ確保に失敗した領域を確認します。DBサーバープロセスで発生した場合、トレースファイルに詳細が残ることがあります。

PGAの使用状況

PGAが過剰に使われていないか、ターゲットやリミットに近づいていないかを確認します。大量ソート、ハッシュ結合、PL/SQL配列処理が候補です。

プロセス単位のメモリ

特定のサーバープロセスだけが異常に大きい場合、特定SQL、バッチ、PL/SQL、メモリリーク疑いを見ます。

OS側のメモリと制限

物理メモリ、スワップ、ulimit、cgroup、Windowsの仮想メモリなど、Oracle外の制限で失敗していないかを確認します。

原因別の当たり付け

ORA-04030は原因が広いため、最初に症状から当たりを付けると調査が早くなります。同じメモリ不足でも、DB全体のPGA不足、特定SQLの暴走、PL/SQLの実装問題、OS側の制限では対処が変わります。

特定バッチだけ失敗する

そのバッチのSQL ID、実行計画、BULK COLLECT、配列サイズ、並列度を優先して確認します。設定変更より処理分割やSQL改善が効くことがあります。

複数処理で同時に発生する

DB全体のPGA、OSメモリ、同時実行数、他プロセスのメモリ使用量を確認します。サーバー全体がメモリ不足になっている可能性があります。

同じプロセスが増え続ける

メモリリーク疑い、長時間セッション、アプリ側のカーソル解放漏れ、巨大なコレクション保持を確認します。再起動だけで終わらせると再発しやすいです。

並列SQLや集計で発生する

ソート、ハッシュ結合、GROUP BY、分析関数、パラレル実行がPGAを使いすぎていないか確認します。並列度を下げるだけで安定することもあります。

ORA-04031との違い

ORA-04030とORA-04031はどちらもメモリ不足系ですが、見る場所が違います。ORA-04031は共有プールなどSGA側の共有メモリ不足が中心です。一方、ORA-04030はサーバープロセスなどが持つ私有メモリ、つまりPGAやOSプロセスのメモリ上限側を疑います。

ORA-04030

主にPGA、プロセス私有メモリ、OSメモリ、プロセス上限を確認します。大量BULK処理、ソート、ハッシュ結合、並列実行で起きやすいです。

ORA-04031

主に共有プール、ラージプール、SGA断片化、共有メモリ不足を確認します。SQL共有、PL/SQLパッケージ、共有プール設定が論点になります。

共有プール側の切り分けが必要な場合は ORA-04031: 共有メモリを割り当てられません 完全ガイド を参照してください。

PGAの状態を確認する

まず、PGA全体の使用状況を確認します。pga_aggregate_targetpga_aggregate_limit に近づいていないか、自動PGA管理がどの程度メモリを使っているかを見ます。

check-pga-parameters.sql
SHOW PARAMETER pga_aggregate_target;
SHOW PARAMETER pga_aggregate_limit;

SELECT name,
       value,
       isdefault,
       issys_modifiable
FROM v$parameter
WHERE name IN ('pga_aggregate_target', 'pga_aggregate_limit')
ORDER BY name;
check-pgastat.sql
SELECT name,
       value,
       unit
FROM v$pgastat
WHERE name IN (
  'aggregate PGA target parameter',
  'aggregate PGA auto target',
  'total PGA allocated',
  'total PGA inuse',
  'maximum PGA allocated',
  'over allocation count'
)
ORDER BY name;

over allocation count が増えている場合、PGAターゲットを超えてメモリ割り当てが必要になった履歴があります。ただし、これだけで設定不足とは断定できません。どのセッションやSQLがメモリを使っているかまで追います。

メモリを使っているプロセスを探す

次に、プロセス単位のメモリ使用量を見ます。ORA-04030は「DB全体が少しずつ足りない」よりも、特定プロセスが大きくなって失敗しているケースが多いです。

check-process-memory.sql
SELECT p.pid,
       p.spid,
       s.sid,
       s.serial#,
       s.username,
       s.program,
       s.sql_id,
       pm.category,
       ROUND(pm.allocated / 1024 / 1024, 1) AS allocated_mb,
       ROUND(pm.used / 1024 / 1024, 1) AS used_mb,
       ROUND(pm.max_allocated / 1024 / 1024, 1) AS max_allocated_mb
FROM v$process p
JOIN v$session s
  ON s.paddr = p.addr
JOIN v$process_memory pm
  ON pm.pid = p.pid
WHERE s.username IS NOT NULL
ORDER BY pm.allocated DESC;
check-session-pga.sql
SELECT s.sid,
       s.serial#,
       s.username,
       s.program,
       s.sql_id,
       ROUND(p.pga_used_mem / 1024 / 1024, 1) AS pga_used_mb,
       ROUND(p.pga_alloc_mem / 1024 / 1024, 1) AS pga_alloc_mb,
       ROUND(p.pga_max_mem / 1024 / 1024, 1) AS pga_max_mb
FROM v$session s
JOIN v$process p
  ON p.addr = s.paddr
WHERE s.username IS NOT NULL
ORDER BY p.pga_alloc_mem DESC
FETCH FIRST 30 ROWS ONLY;

古いバージョンで FETCH FIRST が使えない場合は、外側で ROWNUM を使って上位件数に絞ってください。対象セッションを強制切断する場合は影響範囲を確認します。手順は セッションの確認・強制切断方法完全ガイド にまとめています。

発生中のSQLを確認する

メモリを多く使っているセッションの SQL_ID が分かったら、SQL本文と実行計画を確認します。大きなソート、ハッシュ結合、集計、並列実行、巨大な中間結果があると、PGAを大きく使うことがあります。

check-current-sql.sql
SELECT sql_id,
       child_number,
       executions,
       rows_processed,
       elapsed_time,
       sql_text
FROM v$sql
WHERE sql_id = '&SQL_ID';
display-sql-plan.sql
SELECT *
FROM table(dbms_xplan.display_cursor('&SQL_ID', NULL, 'ALLSTATS LAST +PEEKED_BINDS'));

実行計画で HASH JOINSORTGROUP BYWINDOW SORTPX 系の処理が大きい場合、SQL改善や並列度の見直しでメモリ使用量を下げられることがあります。

PL/SQLの大量処理で起きるケース

PL/SQLでは、無制限の BULK COLLECT、大きすぎるコレクション、巨大な文字列配列、カーソルを閉じない処理がORA-04030の原因になることがあります。特に「全件を一度に配列へ載せる」実装は危険です。

bad-bulk-collect.sql
DECLARE
  TYPE t_rows IS TABLE OF big_table%ROWTYPE;
  l_rows t_rows;
BEGIN
  SELECT *
  BULK COLLECT INTO l_rows
  FROM big_table;

  -- 全件をメモリに載せるため、件数次第でPGAを圧迫する
END;
/
limit-bulk-collect.sql
DECLARE
  CURSOR c IS
    SELECT * FROM big_table;

  TYPE t_rows IS TABLE OF big_table%ROWTYPE;
  l_rows t_rows;
BEGIN
  OPEN c;
  LOOP
    FETCH c BULK COLLECT INTO l_rows LIMIT 1000;
    EXIT WHEN l_rows.COUNT = 0;

    -- ここで分割処理する
    l_rows.DELETE;
  END LOOP;
  CLOSE c;
END;
/

BULK処理は高速化に有効ですが、LIMITなしで大量データを持つとPGAを圧迫します。実装パターンは PL/SQL バルク処理完全ガイド、カーソル処理の考え方は PL/SQL カーソル完全ガイド も参考になります。

OS側のメモリとプロセス上限を確認する

DB内のPGAだけでなく、OS側の制限も見ます。Linuxでは物理メモリ、スワップ、プロセス上限、ulimit、HugePages、cgroupやコンテナ制限が関係することがあります。Windowsでは仮想メモリやサービスアカウントの制限、同居アプリのメモリ使用量も確認します。

linux-memory-check.sh
free -m
vmstat 1 5
ulimit -a
ps -eo pid,ppid,user,rss,vsz,comm --sort=-rss | head -30
OSメモリ不足ならDB設定だけでは直りません
Oracle以外のアプリ、複数インスタンス、バックアップ処理、監視エージェント、Javaプロセスなどが同じサーバーでメモリを使っている場合、PGA設定を増やすとOS全体のメモリ圧迫が悪化することがあります。

pga_aggregate_limitを増やす前に確認すること

pga_aggregate_limitpga_aggregate_target を増やすと改善するケースはあります。ただし、原因がSQLの巨大な中間結果やPL/SQLの無制限配列なら、設定を増やしても再発を先送りするだけです。

増やしてよい可能性があるケース

DBサーバーに十分な空きメモリがあり、PGA不足が全体的に発生していて、SQLやバッチのメモリ使用も妥当な場合です。

先に処理を直すべきケース

特定SQLだけが極端に大きい、BULK COLLECTが全件取得、並列度が高すぎる、特定プロセスだけ増え続ける場合です。

OS増強を検討するケース

DB以外も含めて物理メモリが不足している、スワップが多い、複数インスタンスの合計メモリが大きすぎる場合です。

change-pga-example.sql
-- 例: 変更する場合は、OSメモリと他インスタンスの使用量を確認してから実施する
ALTER SYSTEM SET pga_aggregate_target = 4G SCOPE=BOTH;
ALTER SYSTEM SET pga_aggregate_limit  = 8G SCOPE=BOTH;

一時対応と恒久対応

一時対応

失敗したバッチを止める、異常にメモリを使うセッションを切断する、同時実行数や並列度を下げる、OSメモリ不足を解消する、といった復旧優先の対応です。

恒久対応

SQL実行計画の改善、BULK処理のLIMIT分割、PGA設定の見直し、サーバーメモリ増強、同居プロセス整理、メモリリーク疑いの調査を行います。

再発防止

PGA使用量、ORA-04030発生、スワップ使用量、バッチ同時実行数を監視し、閾値を超えたら早めに検知できるようにします。

切り分けの流れ

  1. アラートログとトレースで発生時刻、プロセスID、SQL ID、エラー引数を確認する
  2. v$pgastat でPGA全体の逼迫を確認する
  3. v$processv$sessionv$process_memory で大きいプロセスを探す
  4. SQL IDから実行計画を確認し、ソート、ハッシュ結合、並列実行、巨大な中間結果を探す
  5. PL/SQLならBULK COLLECT、配列、カーソル、文字列連結の実装を確認する
  6. OSメモリ、スワップ、ulimit、同居プロセス、複数インスタンスの合計メモリを確認する
  7. 設定変更、SQL修正、処理分割、サーバー増強のどれが適切かを決める

関連エラーとの見分け方

ORA-04031

共有プールなどSGA側の不足を疑います。SQL共有、共有プール断片化、SGA設定が主な確認点です。

ORA-01652

TEMP表領域に一時セグメントを拡張できないエラーです。ソートやハッシュ結合が関係する点は似ていますが、見る場所はTEMP表領域です。詳細は ORA-01652の原因と解決方法 を参照してください。

ORA-00020

プロセス数上限に達したエラーです。メモリ不足ではなく、接続数やプロセス数の上限を確認します。

よくある質問

ORA-04030はPGAを増やせば直りますか?

直る場合はありますが、最初から増やす判断は危険です。特定SQLやPL/SQLが異常にメモリを使っている場合、PGAを増やしても再発を遅らせるだけになります。v$process_memoryv$pgastat、SQL実行計画を確認してから判断します。

ORA-04030とORA-04031はどちらがPGA不足ですか?

主にPGAやプロセス私有メモリを疑うのはORA-04030です。ORA-04031は共有プールなどSGA側の共有メモリ不足を疑います。エラー番号だけで設定を変えず、発生箇所とメモリ種別を分けて確認します。

本番障害時に最初に何を残すべきですか?

発生時刻、アラートログ、トレースファイル、OSメモリ状況、対象セッション、SQL ID、PGA使用量を残します。セッションを切断して復旧する場合も、先にSQL IDとプロセス情報を控えておくと、恒久対応につなげやすくなります。

まとめ

ORA-04030は、Oracleプロセスが必要な私有メモリを確保できないときに発生します。PGAを増やせば直る場合もありますが、実務では特定SQL、PL/SQLの大量配列、並列実行、OSメモリ不足、プロセス上限が原因になっていることも多いです。

まずアラートログとトレースで発生箇所を押さえ、v$pgastatv$process_memoryv$processv$session で対象を絞ります。そのうえで、SQL改善、BULK処理の分割、PGA設定、OSメモリ、同時実行数を順番に見直すのが安全です。

参考