Oracle problems
ORA-04030: Out of Process Memory. Which Process, What It Holds, and the Fix
3 November 2026
ORA-04030 is the operating system saying no: one Oracle server process asked for more private memory, and the host, or a limit on the process, had none left. The error names a number of bytes and says nothing about who used the rest. The process that grew, the kind of memory it grew in and the host numbers behind it are two queries and one look at the server away.
What the error says
ORA-04030: out of process memory when trying to allocate N bytes (heap, name). Oracle's own text: operating system memory was exhausted or a per-process limit on private memory was reached, and a single process cannot go past 32 GB. The three parts of the message are the size of the failed allocation, the heap it was for and the name of the allocation; they are the first hint of what grew, and the incident trace written with the error lists the heaps of the process by size.
Two neighbours mean something else:
- ORA-04036: the instance reached
PGA_AGGREGATE_LIMIT, a limit Oracle set for itself, and ended the biggest sessions on purpose. That page. ORA-04030 is what happens when that limit is 0, too high for the host, or not the memory that ran out. - ORA-04031: the shared pool, which is shared memory in the SGA, not a process. That page.
Which process, and what it holds
The process is often still there, smaller, or the same program is on its way up again. V$PROCESS gives the memory per process with the operating system PID, V$SESSION the session behind it:
SELECT p.spid, p.pname, s.sid, s.username, s.program,
ROUND(p.pga_used_mem / 1024 / 1024) AS used_mb,
ROUND(p.pga_alloc_mem / 1024 / 1024) AS alloc_mb,
ROUND(p.pga_max_mem / 1024 / 1024) AS max_mb,
s.sql_id
FROM v$process p
LEFT JOIN v$session s ON s.paddr = p.addr
ORDER BY p.pga_max_mem DESC
FETCH FIRST 15 ROWS ONLY;
pga_max_mem is the most the process ever had, so the one that failed stays near the top even after it freed everything, and a background process (pname) shows up next to the user sessions. Then the categories of that process from V$PROCESS_MEMORY:
SELECT pm.category,
ROUND(pm.allocated / 1024 / 1024) AS alloc_mb,
ROUND(pm.used / 1024 / 1024) AS used_mb,
ROUND(pm.max_allocated / 1024 / 1024) AS max_mb
FROM v$process_memory pm
JOIN v$process p ON p.pid = pm.pid
WHERE p.spid = :spid
ORDER BY pm.max_allocated DESC;
PL/SQL at the top is a collection or a large variable: rows bulk-collected without a limit, a table copied into an associative array, a CLOB built in a loop. SQL at the top is a work area, a hash join or a sort on far more rows than the plan expected, and V$SESSION.SQL_ID names the statement. A process that reaches 32 GB is leaking, and the trace written with the error says in which heap.
What the host says
The database only sees its own processes; the host decides. Three commands as the oracle user, on the server, complete the picture:
free -g # memory and swap on the host
ulimit -a # the limits of the oracle user
grep -E 'VmPeak|VmRSS' /proc/<spid>/status
Swap in use with little free memory says the host is full, and the first process to ask for a large piece is the one that fails, whoever filled it: the SGA, another instance on the same server, an application server, or the page tables of a large SGA that is not in HugePages. A host with memory to spare and a failing process says the limit is on the process: ulimit -v or -d for the oracle user, or the 32 GB that Oracle itself enforces.
The fix, in order
- Give the instance a limit it can keep. If
PGA_AGGREGATE_LIMITis 0, or larger than what the host has left after the SGA and the operating system, Oracle never steps in before the kernel does. Set it so that SGA, limit and operating system fit in physical memory:ALTER SYSTEM SET pga_aggregate_limit = 12G SCOPE = BOTH;. Then a runaway session gets ORA-04036 and the others carry on. - Fix the program that grows. The category and the SQL_ID from the second query point at it. Collections take rows in batches of a few thousand with
BULK COLLECT ... LIMITand are emptied between batches; a work area in the gigabytes is a plan with a wrong cardinality, fixed where the estimate went wrong, not with more memory. - Give the host its memory back. Put the SGA in HugePages (
USE_LARGE_PAGES = ONLY, withvm.nr_hugepagessized for it) so the page tables of hundreds of processes stop taking the memory the PGA needs; move another instance or an application server off the server; keep swap as a safety margin, not as memory in use. - Lift a process limit that is too low.
ulimit -vand-dfor the oracle user come from/etc/security/limits.conforlimits.d, and a limit set for a smaller server survives an upgrade. Unlimited is normal for both; the instance limit is the real guard.
See it coming
A process does not go from 100 MB to 20 GB in one call; the instance PGA climbs for the hour before, and the host loses free memory along with it. Radar Engine, the detection layer of Scops, watches both without an agent on the server:
| Detector | Clock | When it fires |
|---|---|---|
| PGA near its limit | Live, against pga_aggregate_limit | 85% of the limit, or the limit within the hour at the current climb: Warning. 95%: Critical. |
| Host CPU busy | Live, from the host statistics | 85% or more, with less than half of it from the database: Warning. 95% with a run queue of twice the cores: Critical. A host that has started swapping shows as CPU busy outside the database. |
| Heavy swapping in the alert log | Live, from the alert log | Oracle's own "Heavy swapping observed" warning, the moment it is written. |
The finding shows the climb against the limit with the time left, so the instance limit is set and the program is fixed before the host runs dry, not after the first ORA-04030 and its 2 GB trace file.
Questions
Is ORA-04030 a database bug?
Rarely. It is the host running out, a limit on the process, or a program that grows without bound. The 32 GB mark in a single process is the one case that points at a leak, and the trace written with the error names the heap for the support case.
Why did ORA-04030 appear when PGA_AGGREGATE_LIMIT was far from reached?
Because the limit counts Oracle's PGA, not the host. The SGA, another instance, an application server or the page tables of an SGA outside HugePages fill the host first, and the first large allocation fails, whoever asks. Check free -g before the parameter.
Does raising PGA_AGGREGATE_TARGET help?
No. The target shapes the work areas Oracle can shrink; the memory behind ORA-04030 is usually the kind it cannot shrink, a collection or a variable, or memory the host no longer has. The limit, the program and the host are the three places to look.
Can one session take the whole server down?
Without an instance limit, yes: a process grows until the host swaps, every process slows down, and the kernel ends whichever process it chooses. With PGA_AGGREGATE_LIMIT set within physical memory, that session gets ORA-04036 and the rest of the instance keeps running.
Related problems
- ORA-04036: PGA memory exceeds PGA_AGGREGATE_LIMIT
- ORA-04031: shared pool out of memory
- ORA-00020: maximum number of processes
- All Oracle problems
Sources
- Oracle: ORA-04030, PGA_AGGREGATE_LIMIT, USE_LARGE_PAGES, V$PROCESS, V$PROCESS_MEMORY
- Scops docs: Detector reference