Oracle Scratchpad

August 5, 2021


Filed under: Infrastructure,Oracle — Jonathan Lewis @ 1:10 pm BST Aug 5,2021

When defining memory usage to an Oracle instance you can specify an “SGA target” and a separate “PGA target”; alternatively you could specify a single “Memory target”. I’ve not seen many people using the second option and there are reasons why it’s not a good idea – like the side effect it has on the use of large/huge pages – but a thread appeared on the Oracle Developers’ forum recently asking why the Buffer Cache Advisory section of an AWR report would suggest increasing the buffer cache when the Memory Statistics section showed the PGA+SGA usage to be just 6GB out a declared memory_target of 8GB – why was Oracle “wasting” (or losing) 2GB of memory that the report said could be put to good use.

My first thought was that there was a reporting error – maybe a coding error, maybe a problem of inconsistent definition, so my first piece of advice was to poke around for a little more data; and while that was going on I thought I’d run up an instance specifying a memory_target to see what funny numbers might appear.

My first attempt at instance startup failed because I was using a small machine and had allocated more than half the memory to huge pages – and Oracle didn’t want to use huge pages when the memory target was set, so it ran into various resource problems and let me know that I would need to change a few O/S settings 0 so I reduced the memory_target to something small enough to allow the instance to start.

This is where my memory/sga/pga settings ended when the instance finally started (cut-n-paste with some of the output deleted):

SQL> show parameter target

NAME                                 TYPE        VALUE                          
------------------------------------ ----------- ------------------------------ 
memory_max_target                    big integer 1808M                          
memory_target                        big integer 1808M                          
pga_aggregate_target                 big integer 0                              
sga_target                           big integer 0                              

The 1,808MB was what I’d set in the startup file, and here’s a little corroboration of the figures:

SQL> show sga

Total System Global Area 1895823408 bytes
Fixed Size                  9136176 bytes
Variable Size            1107296256 bytes
Database Buffers          771751936 bytes
Redo Buffers                7639040 bytes

The top line is the sum of the next 4 figures, and the numbers add up to 1,808 MB (with an error of 2,000 bytes) but isn’t it interesting that the total s reported as the Total System Global Area – apparently leaving nothing for the PGA.

How does this compare with information from the next available AWR report.

Memory Statistics
~~~~~~~~~~~~~~~~~                       Begin          End
                                 ------------ ------------
                  Host Mem (MB):      3,692.4      3,692.4
                   SGA use (MB):      1,072.0      1,072.0
                   PGA use (MB):        334.9        381.0
    % Host Mem used for SGA+PGA:        38.10        39.35

Suddenly the SGA is only 1,072MB, while the PGA is now reporting 334MB – which means that somewhere something is failing to report the roughly 400MB. Maybe the “Dynamic Memory Components” section of the AWR will help (I’ve deleted all the zero lines here):

                 Begin Snap     Current         Min         Max   Oper Last Op
Component         Size (Mb)   Size (Mb)   Size (Mb)   Size (Mb)  Count Typ/Mod
--------------- ----------- ----------- ----------- ----------- ------ -------
DEFAULT buffer       704.00      704.00      704.00      752.00      0 SHR/IMM
PGA Target           736.00      736.00      736.00      736.00      0 STA/
SGA Target         1,072.00    1,072.00    1,072.00    1,072.00      0 STA/
Shared IO Pool        48.00       48.00         .00       48.00      0 GRO/IMM
java pool             16.00       16.00       16.00       16.00      0 STA/
large pool            16.00       16.00       16.00       16.00      0 STA/
shared pool          272.00      272.00      272.00      272.00      0 STA/

That seems to be a “Current Size” total of 2,864MB – but luckily we can spot that the presence of the SGA Target in the list means we’re double counting, and the total excluding that line is 1,792MB. That’s a shortfall of 16MB from our declared 1,808MB, but that’s okay because with this small memory target Oracle is operating in 16MB granules and one granule has been reserved for the fixed memory and public redo log buffers.

So we haven’t lost a big chunk of the memory_target – what we (or the OP) are seeing is a variation in the purpose of the two different parts of the AWR. The Memory Statistics tell us about PGA being used (at the moment of the snapshot) by current sessions, not about the memory that is reserved as an “internal” PGA target. Maybe some investigation of the Memory Resize Operations would show us that Oracle has reached this distribution of memory between SGA and PGA over a period of time as a fairly stable position with some movement of granules back and forth between the two. We could also check the summary of Process Memory that appears in the AWR.

Geek stuff

I had overlooked the possibility of simply looking at the Dynamic Memory Components section of the AWR to check whether the “missing” memory was allocated to the PGA,, so in the original thread on the developer forum I supplied a query that I wrote many years ago to run as sys against the x$ksmge (granule map) when suitable v$ didn’t exist, so just for completeness here’s that query with the results:

set linesize 156
set trimspool on
set pagesize  60
set tab off

column indx             format 999
column component        format a20
column cursize          format 9,999
column gransize         format 999,999,999,999
column grantype         format 999
column granstate        format a10

column ct               format 9,999
column total_memory     format 999,999,999,999

break on report
compute sum of total_memory on report

        sct.indx, sct.component, sct.cursize, 
        ge.gransize, ge.grantype, ge.granstate, ct,
        ge.gransize * sct.cursize total_memory
        x$kmgsct        sct,
                ge.grantype, ge.granstate, ge.gransize,
                count(*) ct
                x$ksmge         ge
        group by
                ge.grantype, ge.granstate, ge.gransize
        )       ge
        ge.grantype(+) = sct.grantype
and     sct.cursize != 0
order by
        sct.indx, sct.component, ge.granstate

---- -------------------- ------- ---------------- -------- ---------- ------ ----------------
   0 shared pool               18       16,777,216        1 ALLOC          18      301,989,888
   1 large pool                 1       16,777,216        2 ALLOC           1       16,777,216
   2 java pool                  1       16,777,216        3 ALLOC           1       16,777,216
   5 SGA Target                67
   7 DEFAULT buffer cache      43       16,777,216        9 ALLOC          43      721,420,288
  15 Shared IO Pool             3       16,777,216       17 ALLOC           3       50,331,648
  20 PGA Target                46
sum                                                                              1,107,296,256

As you can see, this reports the SGA and PGA targets in terms of granules available, but neither reports any granules actually allocated. However, adding the 46 PGA Target granules of 16MB to the total memory of (approx) 1.1GB we can see that Oracle is clearly aware of the full 1,808 MB (less the one fixed granule), and the oddity of “lost memory” was simply about the choice of what to report.

Memory Target and O/S

Just for completeness – here’s a pair of extracts from the alert log of the instance startup. The first with memory_target set, the second using the sga_target and pga_aggregate_target and leaving the memory_target unset. I’ve removed a load of lines which were simply the timestamps (separated by microseconds):

Starting ORACLE instance (normal) (OS id: 2025)
 /dev/shm will be used for creating SGA
Large pages will not be used. Only standard 4K pages will be used
Dump of system resources acquired for SHARED GLOBAL AREA (SGA)

 Per process system memlock (soft) limit = 128G
 Expected per process system memlock (soft) limit to lock
 instance MAX SHARED GLOBAL AREA (SGA) into memory: 1808M

 Available system pagesizes:
  4K, 2048K

 Supported system pagesize(s):
        4K       Configured          462853          462853        NONE

 Reason for not supporting certain system pagesizes:
  2048K - Dynamic allocate and free memory regions

Note the warning: Large pages will not be used. Only standard 4K pages will be used. That’s half the machine memory unavailable, and lots of memory used by per-process memory maps

Starting ORACLE instance (normal) (OS id: 2968)
 Sys-V shared memory will be used for creating SGA
Dump of system resources acquired for SHARED GLOBAL AREA (SGA)

 Per process system memlock (soft) limit = 128G
 Expected per process system memlock (soft) limit to lock
 instance MAX SHARED GLOBAL AREA (SGA) into memory: 1122M

 Available system pagesizes:
  4K, 2048K

 Supported system pagesize(s):
        4K       Configured               4               4        NONE
     2048K             1200             561             561        NONE


While I’ve highlighted a couple of details about the differences between memory target and sga/pga target, the main point of this note comes back to something I’ve said many times in the past. When you’re looking at reports (AWR / Statspack / home-grown) you do need to understand the meaning of the figures in the report, and when they don’t seem to make sense you need to cross-check with other sources so that you can be confident that you understand what the figures are showing.

In this case the “Host Memory” usage figures for the PGA probably reflect the current (and instantaneous) usage by Oracle processes, not the granules allocated to the instance by the operating system. There are other parts of the AWR report that tell you how the granules are split between the SGA and PGA, and while I haven’t shown it, there’s a section of the report (Memory Resize Operations) that tells you if the instance has been under pressure to move memory granules between the SGA and PGA.


  1. […] Memory allocation (Aug 2021): SGA target, PGA target, Memory target: where’s the memory going. […]

    Pingback by Troubleshooting catalogue | Oracle Scratchpad — February 1, 2022 @ 11:38 am GMT Feb 1,2022 | Reply

  2. […] know that my memory granule size is 16MB (select * from V$sgainfo). What if Oracle had allocated the first few sections of x$ksuse […]

    Pingback by X$ row sizes | Oracle Scratchpad — March 21, 2022 @ 11:00 am GMT Mar 21,2022 | Reply

RSS feed for comments on this post. TrackBack URI

Comments and related questions are welcome.

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Website Powered by

%d bloggers like this: