ORA-04031 in Production — It’s Almost Never Just About Memory Size

I’ve been called in on ORA-04031 emergencies more times than I can count. The call always sounds the same: “The database is throwing ORA-04031, we can’t allocate shared memory, users are getting errors, what do we do?” And the first response from most DBAs — including experienced ones — is to increase the shared pool or the SGA. Sometimes that’s the right answer. Most of the time, it’s not. And applying the wrong fix means the error comes back in three days.

Let me walk through how I actually diagnose this error, because the methodology matters.


What the Error Is Actually Telling You

ORA-04031: unable to allocate 4096 bytes of shared memory
("shared pool","unknown object","sga heap(1,0)","free memory")

That message contains more information than most people extract from it. The second argument — "shared pool" — tells you which SGA component ran out. It could be the shared pool, the large pool, the streams pool, or the Java pool. The fix depends entirely on which one it is.

The third argument identifies the allocation context. "sga heap(1,0)" means heap 1, subheap 0 — the main shared pool heap. If you see "sga heap(3,0)" or similar, you’re in a subpool, which is a different problem.

The fourth argument — "free memory" — tells you there simply wasn’t a contiguous free chunk large enough. This is fragmentation. Not necessarily total size.

This distinction is critical. You can have a 4GB shared pool with 500MB technically “free” and still get ORA-04031 — because that free memory is scattered in thousands of tiny fragments, and Oracle needs a contiguous 4MB chunk for a new package compilation.


Step 1: Don’t Flush Immediately (Controversial, But Hear Me Out)

Everyone’s first instinct is:

sql

ALTER SYSTEM FLUSH SHARED_POOL;

I understand why. It works. The error goes away for a while. But if you flush before diagnosing, you destroy the evidence. The fragmentation pattern, the objects consuming memory, the allocation failures — all gone.

If the production impact is severe, yes, flush and restore service first. But the moment you do, make a note: “This is a recurring problem. I need to capture it next time.”

Before flushing, try to capture this:

sql

-- Check shared pool usage breakdown
SELECT pool, name, bytes/1024/1024 mb
FROM v$sgastat
WHERE pool = 'shared pool'
ORDER BY bytes DESC;
-- Look at library cache hit ratio
SELECT SUM(pins) pins, SUM(reloads) reloads,
ROUND((1 - SUM(reloads)/SUM(pins)) * 100, 2) hit_ratio
FROM v$librarycache;
-- Look for top memory consumers
SELECT namespace, gets, gethits, pins, pinhits,
invalidations, reloads
FROM v$librarycache
ORDER BY reloads DESC;

High reloads in v$librarycache is one of the clearest signals of fragmentation caused by non-shareable SQL.


Step 2: Diagnose Fragmentation vs. Capacity

Run this query — it’s one of my most-used diagnostics for this error:

sql

SELECT ksmchcls class,
COUNT(*) chunks,
SUM(ksmchsiz)/1024/1024 total_mb,
MAX(ksmchsiz)/1024/1024 largest_chunk_mb,
MIN(ksmchsiz) smallest_bytes
FROM x$ksmsp
WHERE ksmchcls = 'free'
GROUP BY ksmchcls;

If largest_chunk_mb is small (say, under 10MB) while total_mb is large (say, 300MB), you have a fragmentation problem. Oracle has plenty of free memory but can’t find a large enough contiguous chunk. Increasing the shared pool won’t fix this long-term — the same fragmentation will happen again.

Now check for literal SQL:

sql

SELECT COUNT(*), SUBSTR(sql_text, 1, 60) sample_sql
FROM v$sql
GROUP BY SUBSTR(sql_text, 1, 60)
HAVING COUNT(*) = 1
ORDER BY COUNT(*) DESC;

If you see thousands of nearly identical SQL statements that differ only by literal values (WHERE id = 1001, WHERE id = 1002, WHERE id = 1003…), that’s your root cause. Each one gets its own parse tree in the library cache. They don’t share. The shared pool fills with unique, non-reusable cursor objects.


Step 3: Fix the Root Cause — Bind Variables and CURSOR_SHARING

The correct fix is to have developers use bind variables:

sql

-- Bad (literal SQL, one library cache entry per unique value)
SELECT * FROM orders WHERE order_id = 10045;
SELECT * FROM orders WHERE order_id = 10046;
-- Good (one library cache entry shared by all)
SELECT * FROM orders WHERE order_id = :order_id;

In practice, getting developers to change all their SQL takes time you don’t have in a production crisis. The emergency lever is CURSOR_SHARING:

sql

ALTER SYSTEM SET CURSOR_SHARING = FORCE;

This tells Oracle to replace literals with system-generated bind variables at parse time, forcing cursor sharing. It’s not a perfect solution — it can cause optimizer issues in some cases (particularly with histograms and skewed data distributions), but it’s the fastest way to stop the bleeding.

Use CURSOR_SHARING = FORCE as a temporary measure while you track down and fix the literal SQL in your application.

The gold standard is CURSOR_SHARING = EXACT (the default) with properly written application code using bind variables.


Step 4: Check for Large Object Allocations

Sometimes the problem isn’t fragmentation — it’s a single large object that can’t fit. PL/SQL packages, large views with complex WITH clauses, or very deeply nested SQL can require large contiguous allocations at compile time.

sql

-- Check for large objects in shared pool
SELECT namespace, sharable_mem/1024/1024 mb, sql_text
FROM v$sql
WHERE sharable_mem > 5*1024*1024
ORDER BY sharable_mem DESC;
-- Check package sizes
SELECT owner, name, type, sharable_mem/1024
FROM v$db_object_cache
WHERE sharable_mem > 1024*1024
ORDER BY sharable_mem DESC;

If you find a specific package or object consuming disproportionate memory, that’s a code quality problem that needs to be addressed at the source.


Step 5: ASMM — Let Oracle Manage SGA Component Sizes

If you’re still manually specifying SHARED_POOL_SIZE, LARGE_POOL_SIZE, etc., stop. Use Automatic Shared Memory Management (ASMM). Set SGA_TARGET and let Oracle allocate memory dynamically between components based on actual usage.

sql

-- Check if ASMM is enabled
SHOW PARAMETER sga_target;
SHOW PARAMETER memory_target;
-- Enable ASMM (set sga_target to your desired total SGA size)
ALTER SYSTEM SET SGA_TARGET = 8G SCOPE=SPFILE;
ALTER SYSTEM SET SGA_MAX_SIZE = 8G SCOPE=SPFILE;
-- Zero out manually set component sizes (let Oracle manage them)
ALTER SYSTEM SET SHARED_POOL_SIZE = 0 SCOPE=SPFILE;
ALTER SYSTEM SET LARGE_POOL_SIZE = 0 SCOPE=SPFILE;

With ASMM, if the shared pool needs more memory and the buffer cache has headroom, Oracle rebalances automatically. Manual sizing in modern Oracle is almost always the wrong choice unless you have a very specific, well-understood workload.


The Scenario I See Most Often

A 7-year-old application written with an ORM (Hibernate, MyBatis, something homegrown) that generates literal SQL. The application team doesn’t know it’s generating literal SQL — they just use the ORM. Nobody reviewed the actual SQL being sent to the database. The system ran fine for years on a beefy on-prem server. Then either the database was migrated to a smaller cloud instance, or transaction volume grew, or both. And suddenly ORA-04031 starts appearing.

The database isn’t broken. The application has been poorly configured for years, and now the chickens have come home to roost.

The fix: enable CURSOR_SHARING = FORCE immediately, get the ORM team to review their SQL generation settings (most ORMs have a bind variable option — it’s usually just one configuration property), then switch back to CURSOR_SHARING = EXACT once the application is fixed.


Quick Reference Checklist

When you see ORA-04031 in production, work through this sequence:

  1. Identify which pool failed (shared pool, large pool, etc.) from the error text
  2. Capture v$sgastat and x$ksmsp before flushing
  3. Check v$librarycache for high reload ratios
  4. Check v$sql for literal SQL patterns
  5. If fragmentation is confirmed: set CURSOR_SHARING = FORCE as emergency measure
  6. If capacity is confirmed: evaluate ASMM and SGA sizing
  7. Check for oversized individual objects
  8. Plan long-term fix: application bind variable remediation
  9. Revert CURSOR_SHARING to EXACT after application fix

ORA-04031 is always telling you something about application behavior. Listen to it.



Yorum bırakın