Oracle内存结构
SGA的区域信息
SGA(system global area)系统全局区跟一些必须的后台进程合进来称为实例(Instance).说它是全局区是包含了全局变量和数据结构,是系统区是包含了进入整个Oracle Instance的数据结构而不是特定的进程结构.
SGA区域:
SGA大概包括下面四到五种区域:
The fixed area
The variable area
The database blocks area
The log buffer
The instance lock database(for parallel server instances)----OPS&RAC
根据内存的大小,我们可以把The fixed area和The log buffer设为很小.
The fixed area:
SGA中的The fixed area包含了数千个原子变量,以及如latches和指向SGA中其它区域的pointers(指针)等小的数据结构.通过对fixed table内表X$KSMFSV查询(如下)可以获得这些变量的名字,变量类型,大小和在内存中的地址.
SQL> select ksmfsnam, ksmfstyp, ksmfssiz, ksmfsadr
2> from x$ksmfsv;
这些SGA变量的名字是隐藏的而且几乎完全不需要去知道.但是我们可以通过结合fixed table内表X$KSMMEM获得这些变量的值或者检查它们所指向的数据结构.
SQL>select a.ksmmmval from x$ksmmem a where addr=(select addr from x$ksmfsv where ksmfsnam=’kcrfal_’);
SGA中的fixed area的每个组成部分的大小是固定的.也就是说它们是不依靠于其它的初始化参数的设置来进行调整的.fixed area中的所以组成部分的大小相加就是fixed area的大小.
The variable area:
SGA中的the variable area是由large pool和shared pool组成的.large pool的内存大小是动态分配的,而shared pool的内存大小即包含了动态管理的内存又包含了永久性的(已经分配的)内存.实际上,初始化参数shared_pool_size的大小设置是指定shared pool中动态分配的那部分内存的一个大概的SIZES而不是整个shared pool的SIZES
Shared pool中永久性的内存包含各种数据结构如:the buffer headers, processes, sessions, transaction arrays, the enqueue resources , locks, the online rollback segment arrays, various arrays for recording statistics.其中大部分的SIZE是依靠初始参数的设置来确定的.这些初始参数只能在实例被关闭的状态下才能够进行修改.所以这里说的永久性是针对实例打开状态下的生存期而言.简单的一个例子PROCESSES参数.在这个process arrays中的slots用完之后,如果有其它的process想再申请一个process则会失败,因为它们在内存中的大小是在实例启动时预分配的.不能动态修改之.
针对很多永久性的arrays,有很多的X$表都把这些元素做一个记录而成员结构则作为字段.V$视图的数据就是从这些X$表获得.如V$PROCESS是基于X$KSUPR内表的.V$PROCESS视图不包含X$KSUPR的全部字段. X$KSUPR也没有覆盖SGA进程结构的所有成员.
The variable area的在SGA中的SIZES就等于LARGE_POOL_SIZE,SHARED_POOL_SIZE和永久性的内存arrays的SIZE三者相加. 永久性的内存arrays的总的SIZE可以通过初始参数的设置来计算得到.然而,你需要知道从参数获得这些array sizes的方程式,每个array元素大小的字节数,还有array头信息的sizes.这些跟Oracle的版本号和OS有关.实际使用中,我们是不必要计算这个永久性的内存arrays的SIZE的.如果想知道,一个方法就是在STARTUP NOMOUNT数据库时记下the variable area.然后减去参数中LARGE_POOL_SIZE和SHARED_POOL_SIZE的大小就可以.
The database block area:
这个区域是数据库块的拷贝.在Oracle 8i中,buffer数由DB_BLOCK_BUFFERS指定.每个buffer的大小由DB_BLOCK_SIZE指定.所以这个区域的大小是两者相乘.在Oracle 9i中,这个区域的大小是DB_CACHE_SIZE指定.这个区不包含它们自己的控制结构,只包含database block copies data.每个buffer的header信息存在于SGA的the variable area中.还有latches信息也放在SGA的the variable area中.在设置DB_BLOCK_BUFFERS时每4个BUFFERS会影响the variable area的1K的SIZE.关于这一点.可以通过测试(针对8i而言).
The log buffer:
这个区域的SIZE是由参数LOG_BUFFER指定的.如果OS支持内存保护,log buffer将会被两个保护页面包围起来以免被一些ORACLE的错误进程损坏log buffer.在SGA中,跟其它的如variable area和database block area相比,log buffer是非常小的.log buffer分成内部的buffer blocks,而这些block各有8个字节的头部信息存在于variable area中.
The instance lock database
在OPS/RAC配置中,instance locks用来控制由所有instances共享的资源以串行的方式被进入并使用.SGA中的这个区域所维护的是本地实例所要使用的数据库资源,所有实例和进程都会用到的数据库资源,还有所有实例和进程当前需要的或者已经拥有的锁(LOCKS).这三个arrays的SIZE分别由参数LM_RESS,LM_PROCS,LM_LOCKS参数指定.(这三个参数是RAC的参数,在单实例中用SHOW PARAMETER是查看不到的). The instance lock database还包含了message buffers和其它的structure.但是其SIZE是非常小的.
这个区域的SIZE是没办法在实例启动的时候看到的.这是Oracle Internals.可以用ORADEBUG工具查看.SQL>ORADEBUG IPC.至于ORADEBUG工具就不做介绍.用这个工具做操作时需要经过Oracle Support同意.
可以用以下的两种方式DUMP SGA:
SQL>ALTER SESSION SET EVENTS 'immediate trace name global_area level 2';
或者SQL>ORADEBUG DUMP GLOBAL_AREA 2
The Shared Pool
The Shared Pool在SGA中是SIZE较大的一个部分.有很多DBA没搞明白Shared Pool是用来做什么的,不知道怎么定Shared Pool的合适的SIZE.就随意的将它的SIZE搞得很大.有时候可能是不够大,但更多的时候是在浪费内存空间.而且太大的Shared Pool会影响性能.
块(Chunk):
要更好的理解Shared Pool,得对X$KSMSP表多做点研究.这个表中的每一个记录行对应的是Shared Pool内存中的一个Chunk(块).
SQL> select ksmchcom, ksmchcls, ksmchsiz from x$ksmsp;
KSMCHCOM KSMCHCLS KSMCHSIZ
---------------- -------- ----------
KGL handles recr 496
PL/SQL MPCODE recr 1624
dictionary cach freeabl 4256
free memory free 1088
library cache freeabl 568
library cache recr 584
multiblock rea freeabl 2072
permanent memor perm 1677104
row cache lru recr 48
session param v freeabl 2936
sql area freeabl 2104
sql area recr 1208
上面的是对这个表查询的例子.(对整个表的查询有5726行左右的记录)
在每个Shared Pool Chunk已经分配好之后,代码将语句转化并使其有作用的这一过程实际上就称为一次分配.这个语句可以在X$KSMSP表中的KSMCHCOM字段看到,描述分配的内存Chunk.每一个Chunk都要比它所包含的对象要大,因为每个Chunk都有多出来16字节的头信息用于存储确认Chunk的类型、类别和大小SIZE还有用于Shared Pool管理的链接指针.
内存Chunk主要有四种类别,可以从X$KSMSP表中的KSMCHCLS看到.
free:这种类别的Chunk称为Free Chunk.它不包含有效的对象,可以自由分配.
recr:可重建的Chunk(Recreatable Chunk),这种Chunk有包含对象,而这些对象在必要的时候是可以临时被删除并在有需要的情况下进行重建.一个例子,包含Shared SQL Statements的Chunks就可以重建
freeabl:可释放的Chunk(Freeabl Chunk),这种Chunk也有包含对象,这些对象在一个session的生存期间是经常可用的而在session断掉之后就不可用.这些Chunks可以在session断开之前进行释放,可以部分释放也可以全部释放.Freeable Chunk是不能临时被删除的,因为它是不可重建的.
perm:永久性的内存Chunk(Permanent memory Chunk).它包含的对象是不能被释放的,是永久存在于内存中的.一些大的永久性的内存Chunk内部也包含一定量的free space.可以根据需要释放给shared poo.
select
ksmchcom contents,
count(*) chunks,
sum(decode(ksmchcls, 'recr', ksmchsiz)) recreatable,
sum(decode(ksmchcls, 'freeabl', ksmchsiz)) freeable,
sum(ksmchsiz) total
from
sys.x_$ksmsp
where
inst_id = userenv('Instance') and
ksmchcls not like 'R%'
group by
ksmchcom
KSMCHCOM CHUNKS RECR FREEABL TOTAL
---------------- ---------- ---------- ---------- ----------
KGFF heap 6 1296 2528 3824
KGK contexts 2 2400 2400
KGK heap 2 1136 1136
KGL handles 571 178616 178616
KQLS heap 404 87952 524888 612840
PL/SQL DIANA 274 42168 459504 501672
PL/SQL MPCODE 57 14560 88384 102944
PLS cca hp desc 1 168 168
PLS non-lib hp 1 2104 2104
character set m 5 23504 23504
dictionary cach 108 223872 223872
fixed allocatio 9 360 360
free memory 185 614088
kzull 1 48 48
library cache 1612 268312 356312 624624
multiblock rea 1 2072 2072
permanent memor 1 1677104
reserved stoppe 2 48
row cache lru 24 1168 1168
session param v 8 23488 23488
sql area 983 231080 1303792 1534872
table columns 19 18520 18520
table definiti 2 176 176
上面这个查询可以得到Shared Pool中所有Chunks的类型,类别和大小SIZE等相关信息.上面只列出部分记录.
Free Lists:
Shared Pool中的Free Chunks,于它们的大小为基准被组织成Free Lists或者Buckets.下面的一张表是Bucket号和Free Chunks SIZE的对应关系:
用下面这个脚本可以查询到Chunks数和每个Free List中的Free Space量.
select
decode(sign(ksmchsiz - 80), -1, 0, trunc(1/log(ksmchsiz - 15, 2)) - 5)
bucket,
sum(ksmchsiz) free_space,
count(*) free_chunks,
trunc(avg(ksmchsiz)) average_size,
max(ksmchsiz) biggest
from
sys.x_$ksmsp
where
inst_id = userenv('Instance') and
ksmchcls = 'free'
group by
decode(sign(ksmchsiz - 80), -1, 0, trunc(1/log(ksmchsiz - 15, 2)) - 5)
BUCKET FREE_SPACE FREE_CHUNKS AVERAGE_SIZE BIGGEST
---------- ---------- ----------- ------------ ----------
0 166344 3872 42 72
1 32208 374 86 96
4 928 1 928 928
6 11784 4 2946 3328
当一个进程需要Shared Pool Memory分配一个Chunk时,它首先会到Free Lists中查找与它所需的SIZE匹配的Chunk.如果跟所需的SIZE没有确切相符的Chunk可以分配则会继续在Free Lists中寻找一个更大的Chunk.如果找到的Chunk有24字节或者更多,则这个Chunk将会被分裂开来使用,将其余的Free Space部分返还到Free Lists中.如果上面的都找不到,则会从一个非空的Free Lists中找一个最小的Chunk给它使用.最后的方式是以LRU机制对Free Lists进行描述
Free Lists的描述,管理和Chunk的分配都是在Shared Pool Lathes的保护下进行的.如果Shared Pool包含有大量的小的Free Chunks时,在对这个特殊的Free Lists进行描述时,Shared Pool Lathes将会被占有比较长的一段时间.实际上,经常出现的Shared Pool Lathes的竞争和等待就是因为包含了大量的小的Free Chunks.所以增加Shared Pool 的SIZE并不能减少Shared Pool Lathes Contention而且还会使得这个竞争更加严重,这就是前面提到的将Shared Pool的SIZE设为很大并不一定会提高性能原因.
LRU Lists:
如果一个进程没办法从Shared Pool Free Lists中获得一个Free Chunk,则它会从Shared Pool中删除一个包含有Recreatable对象的Chunks来释放足够大的Chunks满足自己的使用.
Recreatable Chunks有两个种类:一种是Pinned在内存中的,一种是没有Pinned在内存中的.Pinned在内存中的Chunks跟用DBMS_SHARED_POOL.KEEP执行来KEEP在Shared Pool中是不一样的. DBMS_SHARED_POOL.KEEP是需要DBA来干预执行的,并且只能放在library cache中.而Pinned Chunks是自动执行的,它在Chunks包含正在使用的对象时就会自动被pinned在Shared Pool中.Pinned Recreatable Chunks是不能释放空间的,而Unpinned Recreatable Chunks是可以释放出来的.
在Shared Pool中,Unpinned Chunks被组织成两个Lists,它们都是以LRU机制来排列的.分别被称为临时的LRU List和循环的LRU List. Chunks在Unpinned时放在MRU(most recently used)的最后面,在它们pinned时将会从这个MRU List中删除.
在一个进程需要新分配一部分Shared Pool Memory内存时,Chunks也会从LRU List的最尾端删除.Chunks以每8个chunks为一个集而被flushed(暂时说为清空)-----首先是从临时的LRU List,然后再从循环的LRU List. Chunks是在不考虑SIZE的大小并且以LRU机制被flushed的.有一些Chunks是不能被 flushed的,如用DBMS_SHARED_POOL.KEEP执行后的包含library cache 对象的Chunks是不能被 flushed.这些Chunks通过pinned方式来代替被删除.
Unpinned Recreatable Chunks两种类型的LRU Lists: 临时的LRU List和循环的LRU List的长度可以从fixed表X$KGHLU查询到,还有已经flush掉的Chunks数,由于pinned和unpinned而加入到LRU List或者是从LRU List删除的Chunks数.从X$KGHLU表也可以知道LRU Lists被flushed完全但不成功(不理解)的次数和最近一次请求Chunk失败的所需要Chunk SIZE.具体看下面的语句:
column kghlurcr heading "RECURRENT|CHUNKS"
column kghlutrn heading "TRANSIENT|CHUNKS"
column kghlufsh heading "FLUSHED|CHUNKS"
column kghluops heading "PINS AND|RELEASES"
column kghlunfu heading "ORA-4031|ERRORS"
column kghlunfs heading "LAST ERROR|SIZE"
select
kghlurcr,
kghlutrn,
kghlufsh,
kghluops,
kghlunfu,
kghlunfs
from
sys.x_$kghlu
where
inst_id = userenv('Instance')
/
RECURRENT TRANSIENT FLUSHED PINS AND ORA-4031 LAST ERROR
CHUNKS CHUNKS CHUNKS RELEASES ERRORS SIZE
---------- ---------- ---------- ---------- ---------- -----------
121 164 148447 4126701 0 0
LRU Lists的长度和flush率跟前台应用和工作流量的变化有很大的依赖关系.长或短的LRU Lists都不会造成问题,但是Chunks flush则在对内存的健康管理中占用很重要的一部分.如果TRANSIENT CHUNKS长于RECURRENT CHUNKS则说明Shared Pool SIZE太大了.而Chunks flush到其它的LRU操作的命中率如果大于1/20则说明Shared Pool SIZE太小.(上面这个是别人的经验介绍)
Spare free memory:
如果一个大的内存请求从Free Lists和LRU Lists Flushing都不能分配,Oracle则会用另外的一种方式来实现.
Oracle的重排序并不是用来接合空闲内存的.当一些Chunks已经被释放它们将会跟后面的Chunk接合一起使用(这里所谓的接合是前面一个free chunk跟后面一个free chunk接合在一起成为一个更大的free chunk).一般地,Oracle只会在显示的执行命令ALTER SYSTEM FLUSH SHARED POOL后才会以完全的方式来接合Shared Pool中的free space.即使当Shared Pool有足够的连续的内存段时,内存请求分配也有可能失败的.如果空闲内存被分成多个小的Chunks时,也有可能没法满足大的内存请求分配.
为了满足较大的内存请求分配,Oracle用重排序的方式来释放更多的内存给Shared Pool. 实际上,Oracle在实例启动的时候只分配大概一半的原Shared Pool SIZE给Shared Pool(即划分shared_pool_size的一半内存出来给Shared Pool.等以后需要用到更多时再用重排序的方式秋释放给它).Oracle用这种方式来确保Shared Pool不会产生太多的碎片.
Oracle的多余空闲内存(Spare free memory),在Shared Pool中被隐藏在永久性的内存Chunks(permanent memory chunks)中.这些内存不在Shared Pool的Free Lists中,所以是不能立即被分配出来使用的.在V$SGASTAT可以看到free memory statistics.在有必要的时候Spare Free Memory Chunks才会被释放给Shared Pool.在这些Spare Free Memory已经被分配完给Shared Pool之后,还有对Shared Pool Memory请求但是分配不到Free Memory,则会产生ORA-4031’unable to allocate x bytes of shared memory’错误.如果在数据库运行于高峰登录量一段时间之后,Oracle还有剩余较大部分的Spare Free Memory则说明此时所设置的shared_pool_size过大.可以通过下面的脚本查看剩余的Spare Free Memory.
select
avg(v.value) shared_pool_size,
greatest(avg(s.ksmsslen) - sum(p.ksmchsiz), 0) spare_free,
to_char(
100 * greatest(avg(s.ksmsslen) - sum(p.ksmchsiz), 0) / avg(v.value),
'99999'
) || '%' wastage
from
sys.x_$ksmss s,
sys.x_$ksmsp p,
sys.v_$parameter v
where
s.inst_id = userenv('Instance') and
p.inst_id = userenv('Instance') and
p.ksmchcom = 'free memory' and
s.ksmssnam = 'free memory' and
v.name = 'shared_pool_size'
/
The Reserved List:
一般,最大的Chunks也不会超过5000bytes的.如果有请求更大的Chunks的话,Oracle用的是另外一种方式,即下面说的Reserved Shared Pool,而不会到Shared Pool Free Lists和LRU Lists中寻找适应的或者更大SIZE的Chunks来给它使用.
Oracle为大的Chunks保留了Shared Pool的一部分.缺省保留的是shared_pool_size的5%.也可以通过参数shared_pool_reserved_size设置其大小.对应参数名,这一部分是从Shared Pool中取出的一部分SIZE.
超过5000bytes的Chunks会被放到Shared Pool的保留部分中,开始是可以通过隐含参数_SHARED_POOL_RESERVED_MIN_ALLOC来设置的,但是在实例启动之后是不能修改的.所以小的Chunks是不会被放到Shared Pool的保留部分中来的. Shared Pool的保留部分中的Free Memory不被包含在一般的Shared Pool Free Lists中,而是放在一个单独的Reserved Free List(针对Reserved Shared Pool)中.然而, Reserved Shared Pool是没有属于它自己的LRU Lists 来为Unpinned Recreatable Chunks服务的.因此,在为一般的Free Lists释放内存空间时大的Chunks是不会被flushed(清空)的.而在为Reserved Shared Pool Free Lists释放内存空间时,小的Chunks是不会被flushed(Reserved Shared Pool Free Lists只有大的Chunks).(这里的大的Chunks我们指的是超过5000bytes的Chunks)
在V$SHARED_POOL_RESERVED视图我们可以查看Reserved Shared Pool的统计信息.特别是字段REQUEST_MISSES,它显示的是从Reserved Shared Pool Free Lists中请求大的Chunks没有即刻满足的次数.这个值应当为0.也就是说,在没有flush Unpinned Recreatable Chunks的情况下在Reserved Shared Pool应该有足够多的Free Memory来满足短时间的Freeable memory的请求.查看V$SHARED_POOL_RESERVED视图中的USED_SPACE字段来确定多大的Reserved Shared Pool SIZE才是适当的.用下面的脚本查看Reserved Shared Pool 的SIZE和HWM以及使用率.最好在关闭数据库之前做查询并结合V$RESOURCE_LIMIT查看其它资源的使用.
prompt Reserved Pool High-Water-Mark Since Instance Startup
prompt ====================================================
select
sum(r.ksmchsiz) - &stopper reserved_size,
sum(
r.ksmchsiz -
decode(h.kghlunfu, 0, decode(r.indx, 1, r.ksmchsiz, 0), 0)
) - &stopper high_water_mark,
to_char(
100 * (sum(
r.ksmchsiz -
decode(h.kghlunfu, 0, decode(r.indx, 1, r.ksmchsiz, 0), 0)
) - 48
) / (sum(r.ksmchsiz) - &stopper),
'99999'
) || '%' " USAGE"
from
sys.x_$kghlu h,
sys.x_$ksmspr r
where
h.inst_id = userenv('Instance') and
r.inst_id = userenv('Instance')
/
prompt
RESERVED_SIZE HIGH_WATER_MARK USAGE
------------- --------------- -------
256000 15080 6%
Marking Objects for Keeping:
在一个SIZE适当的SHARED POOL, dead Chunks是不会被清除出去的.任何一个清除的动作都意味着一些有用的对象也会被清除掉的危险.特别是可重建的对象,因为它们只在一定时间内才被使用,但是在它们被重建时的代价可能会很大,因为它们可能是一个很大的对象或者需要更复杂的处理进程.
减轻这个危险性的办法就是用DBMS_SHARED_POOL.KEEP将一些用户自己认为有用的对象KEEP到SHARED POOL中.这个程序将对象以及有关的下级对象放在library cache中并将它们标志为是KEEP在SHARED POOL中的.所以最合适做这个的时间是在实例启动之后做KEEP操作以免SHARED POOL产生更多的碎片.经常会错误的认为如包等大的对象不需要KEEP到SHARED POOL中,因为它们一般会被放到SHARED POOL的RESERVED部分,因此被清除的机率非常小.其实不然,很多大的对象实际上是以多个小的Chunks来分配SHARED POOL内存的,是没办法以它们的大小来获得特殊的保护.通过查看表X$KSMLRU可以确认哪些library cache对象需要KEEP到SHARED POOL中.
Flushing the Shared Pool:
接合连续的free chunks的唯一方法就是用命令ALTER SYSTEM FLUSH SHARED POOL显示的清空SHARED POOL.在实践中,清空SHARED POOL会减少shared pool latch竞争,也会降低产生ORA-4031错误机率,也会减少即刻的性能竞争,特别是那些被KEEP到SHARED POOL中的主要对象.反之,如果那些主对象都已经KEEP到SHARED POOL中了,而且你的SHARED POOL SIZE比较适当,就要少使用FLUSH SHARED POOL,否则,实例将会在正常的运行时间对系统性能的要求特别大.
一般地,会在晚上备份完之后来做FLUSH SHARED POOL.其它的时间就是在SHARED POOL有很多的碎片或者空间不足.在做FLUSH SHARED POOL时要确认不要对CAHED SEQUENCE产生不必要的缺口.要达到这个目的可以将SEQUENCE KEEP到SHARED POOL中,如果是单个实例也可以临时的执行ALTER SEQUENCE NOCACHE.可用下面的PROCEDURE来确认哪些SEQUENCE需要KEEP到SHRAED POOL中.如果需要做SHUTDOWN ABORT来关闭数据库时最好先将SEQUENCE KEEP到SHARED POOL中.
declare
cursor cached_sequences is
select
sequence_owner,
sequence_name
from
sys.dba_sequences
where
cache_size > 0;
sequence_owner varchar2(30);
sequence_name varchar2(30);
begin
open cached_sequences;
loop
fetch cached_sequences into sequence_owner, sequence_name;
exit when cached_sequences%notfound;
sys.dbms_shared_pool.keep(sequence_owner || '.' || sequence_name, 'Q');
end loop;
end;
/
Heaps and Subheaps
针对SHARED POOL的FIXED TABLES X$是以KSM和KGH开头,它们分别代表的意思是Oracle内存管理器和堆管理器模型.两者是紧密联系在一起工作的.内存管理器是负责与操作系统OS进行交互以获得内存供Oracle使用和内存分配信息.堆管理器则是进行动态的内存分配和管理.SHARED POOL也叫SGA HEAP就是这个原因了.
一个堆包含堆描述器和一个或多个内存区,当然也包含子堆.在这种情况下,子堆的堆描述器和内存区是以父堆的Chunks来分配的.HEAP的大小是以HEAP的类型和HEAP’S FREE LIST和LRU LIST的LIST头信息的不同而不同的.每个内存区都有头部信息指向前面的和后面的一个堆,还有此HEAP还有多少空间可分配的信息.
除了Reserved部分,SHARED POOL的子堆实际上跟SHARED POOL本身有相同的结构.内存是以Chunks分配的,Free Chunks被组织成Free Lists. Unpinned Recreatable Chunks也是被组织成两个LRU LISTS: Transient chunks和Recurrent chunks.子堆也有永久性的内存Chunks.也可以再包含子堆,深度为4.
CACHED在SHARED POOL的大部分对象实际上都是在子堆里面为一个新的Chunks查找空间,就好象是SHARED POOL自己为一个新的Chunks查找空间.所不同的是,子堆是以区来增长的,而SHARED POOL是一个固定大小的SIZE.子堆新区是以最小SIZE的区(适合对象的Chunks的最小SIZE)来分配的,所以它一般会找最小的Chunks.
The Large Pool:
如果参数LARGE_POOL_SIZE有设置,则Large Pool将会在SGA中的变量区域(variable area)被配置为一个单独的堆.它不是SHARED POOL的一部分,是以large memory latch来保护的. Large Pool只包含空闲的Chunks和可释放的Chunks.不包含Recreatable Chunks,所以堆管理器的LRU机制是不被使用的.
为了阻止在Large Pool中产生碎片,所有的Large Pool Chunks的SIZE一般都以参数_LARGE_POOL_MIN_ALLOC做为其SIZE,其缺省值为16K.这个参数不必要做调优.
在下列情况下建议你设置LARGE_POOL_SIZE参数使用Large Pool:
使用了MTS
使用了Recovery Manager(RMAN)
使用了并行的查询选项Parallel Query Option(PQO)
The Process Memory:
除了SGA(System Global Area)之外,Oracle进程还使用下面三个全局区:
The Process Global Area (PGA)
The User Global Area (UGA)
The Call Global Area (CGA)
很多人都搞不清楚PGA和UGA两者之间的区别,实际上两者之间的区别跟一个进程和一个会话之间的区别是类似的.尽管说进程和会话之间一般都是一对一的关系,但实际上比这个更复杂.一个很明显的情况是MTS配置,会话往往会比进程多得多.在这种配置下,每一个进程会有一个PGA,每一个会话会有一个UGA.PGA所包含的信息跟会话是无任何关联的,而UGA包含的信息是以特定的会话为基础的.
The PGA:
进程全局区(PGA)即可以理解为Process Global Area,也可以理解为Program Global Area.它的内存段是在进程私有区(Process Private Memory)而不是在共享区(Shared Memory).它是个全局区意味着它包含了所有代码有可能进入的全局变量和数据结构,但是它是不被所有进程共享的.每个Oracle的服务器进程都包含有属于自己的PGA,它只包含了本进程的相关特定信息.PGA中的结构不需要由latches来保护,因为其它的进程是不能进入到这里面来访问的.
PGA包含的是有关进程正在使用的操作系统资源信息以及进程的状态信息,而其它的进程所使用的Oracle的共享资源是在SGA中.PGA是私有的而不是共享的,这个机制是有必要的,因为当进程死掉后可以把这些资源清除和释放掉.
PGA包含两个主要区域:Fixed PGA和Variable PGA或称为PGA Heap. Fixed PGA的作用跟Fixed SGA是类似的,都包含原子变量(不可分的),小的数据结构和指向Variable PGA的指针.
Variable PGA是一个堆.它的Chunks可以从Fixed Table X$KSMPP查看得到,这个表的结构跟前面有提到的X$KSMSP是相同的.PGA HEAP包含了一些有关Fixed Table的永久性内存,它跟某些参数的设置有依赖关系.这些参数包含DB_FILES,LOG_FILES,CONTROL_FILES.
The UGA:
UGA(User Global Area)包含的是特定会话的信息,有如下一些:
所打开游标的持续和运行时间内的区域
包的状态信息,特定的变量
Java会话状态
可以用的ROLES
被ENABLE的跟踪事件
起作用的NLS参数设置
打开的DBLINK
会话的入口控制
跟PGA一样,UGA也由两区组成:Fixed UGA和Variable UGA,也称为UGA HEAP. Fixed UGA包含了大约70个原子变量,小的数据结构和指向Variable UGA的指针.
UGA HEAP中的Chunks可以从它们自己的会话中通过查看表X$KSMUP获得相关信息,这个表的结构跟X$KSMSP是一样的.UGA HEAP包含了一些有关fixed tables的永久性内存段,跟一些参数的设置有依赖关系.这些参数有OPEN_CURSORS,OPEN_LINKS,和MAX_ENABLE_ROLES.
UGA在内存中的位置依赖于会话的配置方式.如果会话连接的配置方式是专用服务器模式(DDS)即是一个会话对应一个进程,则UGA是放在PGA中的.在PGA中,Fixed UGA是其中的一个Chunk,而UGA HEAP是PGA的一个子堆(Subheap).如果会话连接是配置为共享服务器模式(MTS), Fixed UGA是SHARED POOL中的一个Chunk,而UGA HEAP则是SHARED POOL中的子堆(Subheap)
The CGA:
跟其它的全局区不同,Call Global Area是短暂性存在的.它只有在调用数据期间存在,一般是在对实例的最低级别的调用时才需要CGA,如下:
分析一个SQL语句
执行一个SQL语句
取出一个SELECT语句的输出
一个单独的CGA在递归调用时是需要的.在SQL语句的分析过程中,对数据字典信息的递归调用是需要的,因为要对SQL语句进行语法分析,还有在语句的优化期间要计算执行计划.执行PL/SQL块时在处理SQL语句的执行时也是需要递归调用的,在DML语句的执行时要处理触发器执行也是需要递归调用的.
不管UGA是放在PGA中还是在SGA中,CGA都是PGA的一个子堆(Subheap).这个事实的一个重要推论是在一个调用的期间会话必须是一个进程.对于在一个MTS的Oracle数据库进程应用开发时关于这一点的理解是很重要的.如果相应的调用较多,就得增加processes的数量以适应调用的增加.
没有CGA中的数据结构,CALLS是没法工作的.而实际上跟一次CALL相关的数据结构一般都是放在UGA中,如SQL AREA,PL/SQL AREA和SORT AREA它们都必须在UGA中,因为它们要在各CALLS之间要一直存在并且可用.而CGA中所包含的数据结构是要在一次CALL结束后能够释放的.例如CGA包含了关于递归调用的信息,直接I/O BUFFER等还有其它的一些临时性的数据结构.
Java Call Memory也是在CGA中.这一段内存比Oracle的其它内存段管理得更密集.它分成三个Space: Stack Space, New Space, Old Space.在New Space和Old Space中不再被参考使用的Chunks,根据它们在使用期间的长度及SIZE的不同,在调用的执行过程中将被当成不用的Chunks收集起来.New Space Chunks很多次的不用的Chunks的反复收集过程中没有被收集的Chunks将会被放到Old Space Chunks中.这是在Oracle内存管理中唯一的一个废物收集(garbage collection),其它的Oracle内存段都是释放Dead Chunks.
Process Memory Allocation
跟SGA不一样的是,SGA在实例启动之后SIZE就已经是定下来的,而PGA的SIZE是会增长的.通过使用malloc()或者sbrk()系统调用来为进程增加堆数据段大小而使得PGA的SIZE的增长.OS的新虚拟内存会被做为PGA HEAP中的一个新的区被加到PGA中来.这些区一般只几KB大,如果有需要,Oracle将会给分配上千个区.
操作系统对每个进程的堆数据段的增长是有限制的.大部分的情况是操作系统的内存参数进行限制(kernel parameter: MAXDSIZ),有一些情况它的缺省值是可以以每个进程为基准进行修改的.对于所有的进程,操作系统对整个虚拟内存也有一个系统全局性的限制,这个限制跟系统的SWAP SPACE相关.一旦超过了这两个限制,Oracle的进程在执行中会遇到ORA-4030错误.
ORA-4030这个错误的产生一般不是因为每个进程的资源限制而是因为SWAP SPACE空间不足造成.为了诊断这个问题可以使用操作系统的一些选项来查看SWAP SPACE的使用情况.另外,在一些操作系统中,Oracle包含了一个工具叫maxmem,它可以用来查看每个进程可以被分配的堆数据段的最大SIZE以及哪一个限制是第一次超过的.
如果这个问题的出现是因为SWAP SPACE空间不足,而且换页的动作非常频繁而且较多,则需要减少系统一级的虚拟内存的使用,这个可以通过减少进程数也可以通过减少每个进程的内存限制.如果换页动作不频繁而且比较少,则需要调大SWAP SPACE SIZE.
Process Memory Deallocation:
Oracle堆的增长比它们的收缩要来得容易,当然它们的SIZE也是可以收缩的.在V$MYSTAT和V$SESSTAT视图中,session的统计信息session uga memory和session pga memory分别显示了当前session的UGA和PGA的内存大小,包含内部的空闲空间.相应的统计信息session uga memory max 和 session pga memory max分别显示了在session的生存期间所使用过得最大的UGA和最大的PGA.
UGA和PGA只有在特定的操作后才会收缩,这些操作如一次磁盘排序的合并操作,或者用程序DBMS_SESSION.FREE_UNUSED_USER_MEMORY显示释放内存.只有整个free heap extent会被释放给父堆或者是进程堆数据段,所以有一部分的内部free space在内存释放后仍然存在于subheap中.
在大多的操作系统环境下,Oracle是不会减少进程堆数据段也不会释放虚拟内存并将其返还给操作系统的.所以从一个操作系统的查看中,一个Oracle的进程将会把虚拟内存SIZE作为HWM而保留着.如果有必要时,Oracle是会将一些没用的虚拟内存页换页出去的.因为这个原因,有关Oracle进程的虚拟内存页的操作系统统计信息都是很难理解的.所以一般用的是Oracle内部统计信息来代替使用操作系统的统计信息.
程序DBMS_SESSION.FREE_UNUSED_USER_MEMORY只能在连接是配置为MTS模式的应用才能使用.这个最好是少点使用,因为它只释放大的包的array变量所占用的内存返还给Large Pool或者是Shared Pool.一般地,UGA HEAP的内存应该首先被释放,可以通过指派新的空array给array变量使用,也可以通过调用程序DBMS_SESSION.RESET_PACKAGE.
Taking HeapDumps:
Heapdumps可以在当前会话通过使用命令alter system set events或者通过oradebug events命令.Heapdumps将会被写成一个trace文件到进程dump的目录下面(udump),它所包含的信息跟相应的表X$相同.
事件的语法是IMMEDIATE TRACE NAME HEAPDUMP LEVEL n. LEVEL的值可以是如下:1,2,4,8,32.这些值分别对应DUMP出来的信息是PGA,SGA,UGA,CGA,LARGE POOL.
Subheap dump事件的语法是IMMEDIATE TRACE NAME HEAPDUMP_ADDR LEVEL n. n是一个十六位的subheap地址描述符.这些地址可以从KSM X$表中的字段KSMCHPAR得到,也可以从heapdump的文件中的字符串ds=得到
SQL>ALTER SESSION SET TRACEFILE_IDENTIFIER=TEST
SQL>ALTER SESSION SET EVENTS ‘IMMEDIATE TRACE NAME HEAPDUMP LEVEL 1’;
然后到$ORACLE_HOME/ADMIN/UDUMP下找到一个文件名含有TEST的文件用记事本打开,DUMP出来的文件大概如下:
*** 2004-11-30 10:42:09.000
******************************************************
HEAP DUMP heap name="pga heap" desc=067D1FE8---红色可以看到我们DUMP的是哪个HEAP,这里DUMP的PGA.
extent sz=0x213c alt=84 het=32767 rec=0 flg=2 opc=2
parent=00000000 owner=00000000 nex=00000000 xsz=0x25b8
EXTENT 0 addr=07BEB9A4---EXTENT号以及它的地址
Chunk 7beb9ac sz= 9648 freeable "kcrr kcrrpdi ar"
Chunk 7beb9ac---Chunk地址
sz= 9648---这个Chunk的SIZE,以bytes为单位.
freeable----这个Chunk的类型
"kcrr kcrrpdi ar"----这个Chunk的用处描述
EXTENT 1 addr=07BE9854
Chunk 7be985c sz= 8500 perm "perm " alo=7524
EXTENT 2 addr=07BE7474
Chunk 7be747c sz= 9156 freeable "Fixed Uga "
EXTENT 3 addr=07BE5324
Chunk 7be532c sz= 3764 perm "perm " alo=3764
Chunk 7be61e0 sz= 2788 freeable "Alloc environm " ds=07B6ADF4
ds=07B6ADF4-----这个是前面讲到的Subheapdump的level,subheap的地址描述
Chunk 7be6cc4 sz= 540 freeable "kopolal dvoid "
Chunk 7be6ee0 sz= 288 freeable "kopolal dvoid "
Chunk 7be7000 sz= 220 freeable "kopolal dvoid "
Chunk 7be70dc sz= 900 freeable "kopolal dvoid "
EXTENT 4 addr=07BE31D4
Chunk 7be31dc sz= 8440 perm "perm " alo=8440
Chunk 7be52d4 sz= 60 free " "
EXTENT 5 addr=07BE1084
Chunk 7be108c sz= 7096 perm "perm " alo=7096
Chunk 7be2c44 sz= 1140 perm "perm " alo=1140
Chunk 7be30b8 sz= 28 free " "
Chunk 7be30d4 sz= 36 freeable "koh-kghu call h"
Chunk 7be30f8 sz= 200 freeable "PLS cca hp desc"
EXTENT 6 addr=07BB0034
Chunk 7bb003c sz= 3052 perm "perm " alo=3052
Chunk 7bb0c28 sz= 404 perm "perm " alo=404
Chunk 7bb0dbc sz= 56 free " "
Chunk 7bb0df4 sz= 92 freeable "joxp heap "
Chunk 7bb0e50 sz= 36 freeable "external name "
Chunk 7bb0e74 sz= 36 freeable "kzsna:login nam"
Chunk 7bb0e98 sz= 17012 freeable "ksm stack "
EXTENT 7 addr=07B68D34
Chunk 7b68d3c sz= 2000 perm "perm " alo=2000
Chunk 7b6950c sz= 152 perm "perm " alo=152
Chunk 7b695a4 sz= 116 free " "
Chunk 7b69618 sz= 540 freeable "kopolal dvoid "
Chunk 7b69834 sz= 92 freeable "KSFQ heap descr"
Chunk 7b69890 sz= 16 freeable "KSFH indicator "
Chunk 7b698a0 sz= 4144 recreate "Alloc environm " latch=00000000
ds 7b6adf4 sz= 6932 ct= 2
7be61e0 sz= 2788
Chunk 7b6a8d0 sz= 1424 freeable "kpuinit env han"
Total heap size = 81976----这个heap的SIZE,应该是以kb为单位.
FREE LISTS:-----这个PGA Free Lists的一些信息
Bucket 0 size=44---Bucket号以及其对应的Free Chunks SIZE,这个SIZE以bytes为单位.
Chunk 7bb0dbc sz= 56 free " "
Chunk 7be52d4 sz= 60 free " "
Chunk 7be30b8 sz= 28 free " "
Bucket 1 size=76
Bucket 2 size=96
Chunk 7b695a4 sz= 116 free " "
Bucket 3 size=140
Bucket 4 size=236
Bucket 5 size=268
Bucket 6 size=524
Bucket 7 size=1036
Bucket 8 size=2060
Bucket 9 size=4108
Bucket 10 size=8204
Bucket 11 size=16396
Bucket 12 size=32780
Bucket 13 size=65548
Bucket 14 size=131084
Bucket 15 size=262156
Bucket 16 size=524300
Bucket 17 size=2097164
Total free space = 260---以kb为单位.
UNPINNED RECREATABLE CHUNKS (lru first):
PERMANENT CHUNKS:
Chunk 7be985c sz= 8500 perm "perm " alo=7524
Chunk 7be532c sz= 3764 perm "perm " alo=3764
Chunk 7b6950c sz= 152 perm "perm " alo=152
Chunk 7bb0c28 sz= 404 perm "perm " alo=404
Chunk 7be31dc sz= 8440 perm "perm " alo=8440
Chunk 7be2c44 sz= 1140 perm "perm " alo=1140
Chunk 7bb003c sz= 3052 perm "perm " alo=3052
Chunk 7be108c sz= 7096 perm "perm " alo=7096
Chunk 7b68d3c sz= 2000 perm "perm " alo=2000
Permanent space = 34548---以kb为单位.
******************************************************
******************************************************
HEAP DUMP heap name="top call heap" desc=067D46D8
heap name="top call heap"----这个PGA中的CGA信息
extent sz=0x213c alt=92 het=32767 rec=0 flg=2 opc=3
parent=00000000 owner=00000000 nex=00000000 xsz=0xfffc
EXTENT 0 addr=07BF0004
Chunk 7bf000c sz= 32828 perm "perm " alo=136
Chunk 7bf8048 sz= 30552 free " "
Chunk 7bff7a0 sz= 1072 recreate "callheap " latch=00000000
ds 67d3d00 sz= 1072 ct= 1
Chunk 7bffbd0 sz= 1072 recreate "callheap " latch=00000000
ds 67d3d68 sz= 1072 ct= 1
Total heap size = 65524
FREE LISTS:
Bucket 0 size=44
Bucket 1 size=76
Bucket 2 size=96
Bucket 3 size=140
Bucket 4 size=236
Bucket 5 size=268
Bucket 6 size=524
Bucket 7 size=1036
Bucket 8 size=2060
Bucket 9 size=4108
Bucket 10 size=8204
Bucket 11 size=16396
Chunk 7bf8048 sz= 30552 free " "
Bucket 12 size=32780
Bucket 13 size=65548
Bucket 14 size=131084
Bucket 15 size=262156
Bucket 16 size=524300
Bucket 17 size=2097164
Total free space = 30552
UNPINNED RECREATABLE CHUNKS (lru first):
PERMANENT CHUNKS:
Chunk 7bf000c sz= 32828 perm "perm " alo=136
Permanent space = 32828
******************************************************
******************************************************
HEAP DUMP heap name="top uga heap" desc=067D47F8
heap name="top uga heap"---这个PGA中的UGA信息
extent sz=0xffdc alt=92 het=32767 rec=0 flg=2 opc=3
parent=00000000 owner=00000000 nex=00000000 xsz=0x1fffc
EXTENT 0 addr=07C00004
Chunk 7c0000c sz= 48 free " "
Chunk 7c0003c sz= 65476 recreate "session heap " latch=00000000
ds 7be7490 sz= 65476 ct= 1
Total heap size = 65524
FREE LISTS:
Bucket 0 size=44
Chunk 7c0000c sz= 48 free " "
Bucket 1 size=76
Bucket 2 size=96
Bucket 3 size=140
Bucket 4 size=236
Bucket 5 size=268
Bucket 6 size=524
Bucket 7 size=1036
Bucket 8 size=2060
Bucket 9 size=4108
Bucket 10 size=8204
Bucket 11 size=16396
Bucket 12 size=32780
Bucket 13 size=65548
Bucket 14 size=131084
Bucket 15 size=262156
Bucket 16 size=524300
Bucket 17 size=2097164
Total free space = 48
UNPINNED RECREATABLE CHUNKS (lru first):
PERMANENT CHUNKS:
Permanent space = 0