Skip to content

ORA-04031 Unable to Allocate Memory - Shared Pool Solutions

ORA-04031: Unable to Allocate Memory in Shared Pool

Section titled “ORA-04031: Unable to Allocate Memory in Shared Pool”

Error Text: ORA-04031: unable to allocate string bytes of shared memory ("string","string","string","string")

This error occurs when Oracle cannot allocate enough contiguous memory in the shared pool. It’s one of the most common memory-related errors and can severely impact database operations, preventing new connections and causing application failures.

ORA-04031: unable to allocate 4096 bytes of shared memory ("shared pool","SELECT /*+ RULE */ ...","sql area","kglh0^23d1b3c8")
^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^
Size needed Pool name SQL causing issue Heap name
  • shared pool - General shared pool memory
  • large pool - Used for parallel operations, RMAN
  • java pool - Java stored procedures
  • streams pool - Oracle Streams
  • Many hard parses creating small memory chunks
  • Lack of bind variables causing unique SQL statements
  • Memory leaks from bugs
  • Insufficient memory for workload
  • Growth in concurrent users
  • New applications added
  • Not using bind variables
  • Dynamic SQL generation
  • Excessive hard parsing
  • Unpinned large objects
  • Cursor leaks
  • Bug-related memory growth
-- Shared pool summary
SELECT pool, name, bytes/1024/1024 MB
FROM v$sgastat
WHERE pool = 'shared pool'
ORDER BY bytes DESC;
-- Free memory by pool
SELECT pool, ROUND(SUM(bytes)/1024/1024,2) as free_mb
FROM v$sgastat
WHERE name = 'free memory'
GROUP BY pool;
-- Shared pool fragmentation
SELECT bucket,
COUNT(*) free_chunks,
MAX(bytes)/1024 max_kb,
SUM(bytes)/1024/1024 total_mb
FROM v$sgastat
WHERE pool = 'shared pool'
AND name = 'free memory'
GROUP BY bucket
ORDER BY bucket;
-- Memory allocation failures
SELECT request_failures, last_failure_size
FROM v$shared_pool_reserved;
-- Top memory consumers in shared pool
SELECT * FROM (
SELECT owner, name, type, sharable_mem/1024/1024 mb
FROM v$db_object_cache
WHERE sharable_mem > 1048576 -- > 1MB
ORDER BY sharable_mem DESC
) WHERE ROWNUM <= 20;
-- SQL using most memory
SELECT * FROM (
SELECT sql_id,
substr(sql_text,1,50) sql_text,
sharable_mem/1024/1024 mb,
version_count,
loads,
executions
FROM v$sqlarea
WHERE sharable_mem > 1048576
ORDER BY sharable_mem DESC
) WHERE ROWNUM <= 20;
-- Check for cursor leaks
SELECT username,
COUNT(*) open_cursors,
MAX(cursor_count) max_cursors
FROM (
SELECT s.username, s.sid,
(SELECT COUNT(*) FROM v$open_cursor o
WHERE o.sid = s.sid) cursor_count
FROM v$session s
WHERE username IS NOT NULL
)
GROUP BY username
ORDER BY open_cursors DESC;
-- Flush shared pool to free memory
ALTER SYSTEM FLUSH SHARED_POOL;
-- Note: This invalidates all SQL and requires reparsing
-- Only use during maintenance windows or emergencies
-- Check current size
SHOW PARAMETER shared_pool_size;
SHOW PARAMETER sga_target;
-- For manual memory management
ALTER SYSTEM SET shared_pool_size = 2G SCOPE=BOTH;
-- For automatic memory management
ALTER SYSTEM SET sga_target = 10G SCOPE=BOTH;
-- Let Oracle auto-tune shared pool within SGA
-- For AMM (11g+)
ALTER SYSTEM SET memory_target = 12G SCOPE=BOTH;
-- Set reserved pool (5-10% of shared pool)
ALTER SYSTEM SET shared_pool_reserved_size = 200M SCOPE=BOTH;
-- Check reserved pool usage
SELECT request_misses, request_failures,
free_space, used_space, requests
FROM v$shared_pool_reserved;
-- BAD: Unique SQL for each value
String sql = "SELECT * FROM emp WHERE emp_id = " + empId;
-- GOOD: Using bind variables
String sql = "SELECT * FROM emp WHERE emp_id = :1";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, empId);
-- PL/SQL example
DECLARE
v_sql VARCHAR2(1000);
v_emp_id NUMBER := 100;
v_name VARCHAR2(50);
BEGIN
-- BAD
v_sql := 'SELECT name FROM emp WHERE emp_id = ' || v_emp_id;
EXECUTE IMMEDIATE v_sql INTO v_name;
-- GOOD
v_sql := 'SELECT name FROM emp WHERE emp_id = :1';
EXECUTE IMMEDIATE v_sql INTO v_name USING v_emp_id;
END;
/
-- Pin important packages
BEGIN
DBMS_SHARED_POOL.KEEP('SYS.STANDARD', 'P');
DBMS_SHARED_POOL.KEEP('SYS.DBMS_STANDARD', 'P');
DBMS_SHARED_POOL.KEEP('SYS.DBMS_OUTPUT', 'P');
-- Add your critical packages
DBMS_SHARED_POOL.KEEP('APP_SCHEMA.CRITICAL_PKG', 'P');
END;
/
-- View pinned objects
SELECT owner, name, type, kept
FROM v$db_object_cache
WHERE kept = 'YES'
ORDER BY owner, name;
-- Force cursor sharing (use carefully)
ALTER SYSTEM SET cursor_sharing = FORCE SCOPE=BOTH;
-- Options: EXACT (default), SIMILAR (deprecated), FORCE
-- Monitor cursor sharing impact
SELECT force_matching_signature,
COUNT(*) sql_count,
SUM(sharable_mem)/1024/1024 total_mb
FROM v$sqlarea
WHERE force_matching_signature != 0
GROUP BY force_matching_signature
HAVING COUNT(*) > 10
ORDER BY sql_count DESC;
-- Estimate shared pool needs
WITH workload AS (
SELECT
COUNT(DISTINCT sql_id) unique_sqls,
AVG(sharable_mem) avg_sql_size,
SUM(sharable_mem)/1024/1024 total_sql_mb
FROM v$sqlarea
)
SELECT
unique_sqls,
ROUND(avg_sql_size/1024) avg_sql_kb,
ROUND(total_sql_mb) current_sql_mb,
ROUND(total_sql_mb * 1.5) recommended_min_mb,
ROUND(total_sql_mb * 2) recommended_optimal_mb
FROM workload;
-- Library cache hit ratio (should be > 95%)
SELECT
namespace,
ROUND(gethitratio * 100, 2) get_hit_ratio,
ROUND(pinhitratio * 100, 2) pin_hit_ratio,
reloads,
invalidations
FROM v$librarycache
ORDER BY namespace;
-- SGA advisor recommendations
SELECT sga_size,
sga_size_factor,
estd_db_time,
estd_db_time_factor
FROM v$sga_target_advice
ORDER BY sga_size;
-- Shared pool advisor
SELECT shared_pool_size_for_estimate,
shared_pool_size_factor,
estd_lc_time_saved,
estd_lc_memory_object_hits
FROM v$shared_pool_advice
ORDER BY shared_pool_size_for_estimate;
-- Table to track ORA-04031 occurrences
CREATE TABLE dba_04031_history (
error_date TIMESTAMP DEFAULT SYSTIMESTAMP,
pool_name VARCHAR2(30),
request_size NUMBER,
error_message VARCHAR2(500),
sql_text CLOB,
module VARCHAR2(64),
action VARCHAR2(64)
);
-- Procedure to monitor shared pool
CREATE OR REPLACE PROCEDURE monitor_shared_pool AS
v_free_memory NUMBER;
v_pool_size NUMBER;
v_free_pct NUMBER;
BEGIN
-- Get free memory percentage
SELECT SUM(DECODE(name,'free memory',bytes,0)),
SUM(bytes)
INTO v_free_memory, v_pool_size
FROM v$sgastat
WHERE pool = 'shared pool';
v_free_pct := (v_free_memory / v_pool_size) * 100;
-- Alert if free memory < 5%
IF v_free_pct < 5 THEN
DBMS_OUTPUT.PUT_LINE('WARNING: Shared pool free memory at ' ||
ROUND(v_free_pct,2) || '%');
-- Add alerting logic here
END IF;
-- Check for recent failures
FOR rec IN (
SELECT request_failures, last_failure_size
FROM v$shared_pool_reserved
WHERE request_failures > 0
AND last_failure_size > 0
) LOOP
DBMS_OUTPUT.PUT_LINE('Shared pool failures detected: ' ||
rec.request_failures);
END LOOP;
END;
/
-- Create automated flush job for emergencies
CREATE OR REPLACE PROCEDURE auto_flush_shared_pool AS
v_free_mb NUMBER;
BEGIN
-- Get free memory in MB
SELECT SUM(bytes)/1024/1024 INTO v_free_mb
FROM v$sgastat
WHERE pool = 'shared pool' AND name = 'free memory';
-- If free memory < 50MB, flush
IF v_free_mb < 50 THEN
EXECUTE IMMEDIATE 'ALTER SYSTEM FLUSH SHARED_POOL';
-- Log the action
INSERT INTO dba_maintenance_log (
action_date, action_type, action_detail
) VALUES (
SYSTIMESTAMP, 'EMERGENCY_FLUSH',
'Shared pool flushed due to low memory: ' || v_free_mb || 'MB free'
);
COMMIT;
END IF;
END;
/
  1. Always use bind variables
  2. Limit dynamic SQL generation
  3. Close cursors explicitly
  4. Use connection pooling
  5. Prepare statements once, execute many
-- Recommended initial settings
ALTER SYSTEM SET shared_pool_size = 2G SCOPE=SPFILE;
ALTER SYSTEM SET shared_pool_reserved_size = 200M SCOPE=SPFILE;
ALTER SYSTEM SET cursor_sharing = EXACT SCOPE=SPFILE;
ALTER SYSTEM SET open_cursors = 300 SCOPE=SPFILE;
-- For OLTP systems with bind variables
ALTER SYSTEM SET session_cached_cursors = 100 SCOPE=SPFILE;
-- Enable memory advisors
ALTER SYSTEM SET statistics_level = TYPICAL SCOPE=SPFILE;
-- Weekly shared pool analysis
SET SERVEROUTPUT ON
DECLARE
v_sql_reuse_pct NUMBER;
v_single_use_sql NUMBER;
BEGIN
-- Check SQL reuse
SELECT (1 - (single_use_sql/total_sql)) * 100,
single_use_sql
INTO v_sql_reuse_pct, v_single_use_sql
FROM (
SELECT COUNT(*) total_sql,
SUM(CASE WHEN executions = 1 THEN 1 ELSE 0 END) single_use_sql
FROM v$sqlarea
);
DBMS_OUTPUT.PUT_LINE('SQL Reuse: ' || ROUND(v_sql_reuse_pct,2) || '%');
DBMS_OUTPUT.PUT_LINE('Single-use SQL: ' || v_single_use_sql);
IF v_sql_reuse_pct < 80 THEN
DBMS_OUTPUT.PUT_LINE('WARNING: Poor SQL reuse indicates bind variable issues');
END IF;
END;
/
  • ORA-04030 - Out of process memory (PGA)
  • ORA-00604 - Error occurred at recursive SQL level
  • ORA-01000 - Maximum open cursors exceeded
  • ORA-12520 - TNS:listener could not find handler
  1. Flush shared pool (immediate relief)

    ALTER SYSTEM FLUSH SHARED_POOL;
  2. Increase memory (if possible)

    ALTER SYSTEM SET shared_pool_size = 3G SCOPE=MEMORY;
  3. Kill problematic sessions

    -- Find sessions with many open cursors
    SELECT sid, serial#, username, program
    FROM v$session
    WHERE sid IN (
    SELECT sid FROM v$open_cursor
    GROUP BY sid HAVING COUNT(*) > 200
    );
  4. Enable cursor sharing (temporary)

    ALTER SYSTEM SET cursor_sharing = FORCE SCOPE=MEMORY;