all about Oracle memory - 错误处理

 

3.内存错误处理

Oracle中最常见的内存错误就是4030和4031错误。这两个错误分别是在分配PGA和SGA时,没有足够内存分配导致的。经过我们以上对Oracle内存的了解以及对内存管理机制的浅析,可以总结在这两种错误发生时,我们该如何分析和处理。

3.1.分析、定位ORA-4030

4030错误是由于oracle进程在内存扩展时,无法从OS获取到所需的内存而产生的报错。在专有服务模式下,Oracle进程的内存包括堆栈、PGA、UGA(从PGA中分配)和有些进程信息;而MTS下,UGA是从SGA中分配,不包括在进程的内存范围内。

3.1.1.4030错误产生的原因

PGA的大小不是固定的,是可以扩展的。PGA通过系统调用扩展堆数据段时,操作系统分配新的虚拟内存给进程作为PGA扩展段。这些扩展段一般是几个KB。只要需要,oracle会分配几千个扩展段。然而,操作系统限制了一个进程的堆数据段的增长。在UNIX中,这个限制一般受到OS内核参数MAXDSIZ限制,这是限制单个进程的。还有一个对所有进程的虚拟内存的总和大小的限制。这个限制和swap交换空间(虚拟内存)大小有关。如果在扩展PGA内存时达到这些限制,就会抛4030错误。

3.1.2.4030错误分析

既然知道了4030错误产生的可能原因,我们在分析4030错误时,就可以从这几个方面分别收集信息进行分析,并结合Oracle进程内存的使用情况来解决问题。

3.1.2.1.操作系统是否由足够的内存

在不同的操作系统下,我们可以使用相应的工具来收集系统的内存使用情况,以判断内存是否足够:

OpenVMS systems

可以使用show memory查看物理内存和虚拟内存页的使用情况

Physical Memory Usage (pages):   Total      Free      In Use    Modified
 
  Main Memory (256.00Mb)                       32768      24849      7500     419
 
 .....
 
Paging File Usage (blocks):                     Free   Reservable  Total
 DISK$BOBBIEAXPSYS:[SYS0.SYSEXE]SWAPFILE.SYS    30720   30720      39936
 
 DISK$BOBBIEAXPSYS:[SYS0.SYSEXE]PAGEFILE.SYS    226160  201088    249984
 
 DISK$BOBBIE_USER3:[SYS0.PAGEFILE]PAGEFILE.SYS  462224  405296    499968

一般情况下,空闲pagefile的之和不能小于它的总数之和的一半。而且SWAPFILE必须是始终没有被使用的,它的空闲页必须和总页数相同。

Windows

Windows下可以通过任务管理器的性能页来查看内存的使用情况,也可以使用TopShow来观察系统进程的内存使用情况

UNIX

不同厂商的UNIX下,各种工具的使用和统计结果可能有所不同。常用的对内存的查看工具主要有:

oTOP —— 查看物理内存和交换空间

ovmstat —— 查看物理内存和交换空间状况,以及观察是否有pageout/page in

oswapon -s —— 查看交换空间情况

oswapinfo -mt —— 查看交换空间使用情况

下面是swapinfo的一个输出:

> swapinfo -mt

             Mb      Mb     Mb   PCT  START/     Mb

TYPE      AVAIL   USED    FREE  USED   LIMITRESERVE  PRI  NAME

dev        4096       0   4096    0%       0      -    1  /dev/vg00/lvol2

dev        8000       0   8000    0%       0      -    1  /dev/vg00/swap2

reserve       -  12026  -12026

memory    20468  13387    7081   65%

total     32564  25413    7151   78%      -       0    -

 

此外,在一些操作系统中,还可以通过Oracle自己提供的工具maxmem来检查一个进程能够分配的最大堆数据段的大小。

> maxmem

Memory starts at: 6917529027641212928(6000000000020000)

Memory ends at:   6917529031936049152 (6000000100000000)

Memory available: 4294836224(fffe0000)

3.1.2.2.是否受到系统限制

在操作系统,往往会有对单个进程或者所有进程能够分配的内存大小做了限制。当Oracle分配进程内存时,如果达到这些限制,也会导致4030错误。在不同操作系统中,可以用不同方式检查系统是否有做限制。OpenVMS systems:

show process/id=<process id>/quota可以显示一个进程的可用配额是多少。

Windows

如前所述,在window 32位系统中,进程的可用内存限制为2G(可以通过其他方式突破此限制)。而windows下,oracle是以一个单独进程方式运行的,它的内存包括了堆栈、SGA、PGA。我们可以通过任务管理器或TopShow来检查Oracle进程是否达到此限制。

UNIX

可以使用命令ulimit来查看unix下的限制:

> ulimit -a

time(seconds)        unlimited

file(blocks)         unlimited

data(kbytes)         1048576

stack(kbytes)        131072

memory(kbytes)       unlimited

coredump(blocks)     4194303

3.1.2.3.哪个Oracle进程请求了过多的内存

有些进程会做某些操作时会需要分配大量内存,如使用了PL/SQL TABLE或者做排序时。如果这样的进程在系统中运行一段时间后,就可能导致4030错误的产生。我们可以用以下语句来查看各个进程的内存使用情况:

select

   sid,name,value

from

   v$statname n,v$sesstat s

where

   n.STATISTIC# = s.STATISTIC# and

   name like ‘%ga %‘

order by 3 asc;

 

同时,我们还可以从操作系统的角度来确认这些大量消耗内存的进程。

OpenVMS systems

show process/continious可以查看各个进程的物理和虚拟内存的使用情况。

Windows

在windows中,由于Oracle是以一个单独进程运行的,而由线程来服务于会话的。因此无法查看单个会话的内存占用情况。

UNIX

UNIX中,可以通过ps -lef|grep ora来查看oracle进程占用的内存情况。

3.1.2.4.收集进程正在进行的操作

在解决4030问题时,有一点很重要,抛出4030错误的进程并不一定是导致内存不足的进程。只不过在它请求分配内存时,内存已经不足了。很有可能在此之前就已经有大量消耗内存的进程导致内存不足。你需要找出内存消耗不断增长的进程,观察它进行的操作。这条语句可以查出会话进程正在执行的语句:

select sql_text 

from v$sqlarea a, v$sessions

where a.address = s.sql_addressand s.sid = <SID>;

 

另外,可以做一个heapdump,将结果发给Oracle进行分析,

SQL> oradebug unlimit

 

SQL> oradebug setorapid<PID> (通过v$process查到的pid, 用setospid来设置OS中的PID【或者v$process中的spid】)

 

SQL> oradebug dump heapdump7 (1-PGA; 2-Shared Pool; 4-UGA; 8-CGA; 16-top CGA; 32-large pool)

SQL> alter session setevents ‘4030 trace name heapdump level 25‘;

3.1.3.解决4030错误的建议

如果问题是由于swap空间不足造成的,并且由中度或者严重的pagein/page out(可以用vmstat查看),你就需要尝试降低系统整体的虚拟内存的使用(如调整SGA大小),或者降低单个进程内存的使用(如调整sort_area_size),或者减少进程数量(如限制processes参数,使用MTS)。而如果page in/page out很少或者根本没有,就可以考虑增大swap空间。某些系统中,可以考虑使用伪交换区(如hp-ux中,可以考虑设置swapmen_on)。

如果问题和PLSQL操作有关,可以,1、检查PLSQL中的TABLE,看看其中的数据是否全都必要,是否可以减少数据放入TABLE中;2、优化相关语句(比如通过调整优化器策略,使查询计划走sort比较少的访问路径),减少sort操作,或者减少sort_area_size(代价就是一部分sort操作会放在磁盘上进行,降低性能)。

9i以后可以考虑设置PGA内存自动管理。即设置PGA_AGGREGATE_TARGET在一定数值范围内,WORKAREA_SIZE_POLICY设置为AUTO。但是注意,9i在OpenVMS系统上、或者在MTS模式下不支持PGA内存自动关联。

如果是因为进程数过多导致的内存大量消耗,首先可以考虑调整客户端,减少不必要的会话连接,或者采用连接池等方式,以保持系统有稳定的连接数。如果会话非常多,且无法降低的话,可以考虑采用MTS,以减少Oracle进程数。

检查SGA中的内存区是否分配过多(如shared pool、large pool、java pool)等,尝试减少SGA的内存大小。

在windows下,可以尝试使用ORASTACK来减少线程的堆栈大小,以释放更多的内存。

考虑增加物理内存。

3.2.分析、定位ORA-4031

4031错误是Oracle在没有足够的连续空闲空间分配给Shared Pool或者Large Pool时抛出的错误。

3.2.1.4031错误产生的原因

前面我们描述Shared Pool的空闲空间的请求、分配过程。在受到空闲空间请求时,内存管理模块会先查找空闲列表,看是否有合适的空闲chunk,如果没有,则尝试从LRU链表中寻找可释放的chunk,最终还未找到合适的空闲chunk就会抛出4031错误。

在讨论4031问题之前,可以先到第一章中找到与shared pool(shared_pool_size、shared_pool_reserved_size、shared_pool_reserved_min_alloc)和large pool(large_pool_size)的参数描述,再了解一下这些参数的作用。这对于理解和分析4031错误会很有帮助。此外,还需要再回顾以下10g以后的SGA内存自动关联部分(相关参数是SGA_TARGET),因为使用这一特性,能大大减少4031错误产生的几率。

3.2.2.4031错误分析

通常,大多数的4031错误都是和shared pool相关的。因此,4031错误的分析,主要是对shared pool的分析。

3.2.2.1.对shared pool的分析

当4031错误提示是shared pool无足够连续内存可分配时,有可能是由于shared pool不足或者shared pool中严重的碎片导致的。

Shared pool不足分析

视图V$SHARED_POOL_RESERVED中可以查询到产生4031的一些统计数据、以及shared pool中保留区(前面说了,保留区是用来缓存超过一定大小的对象的shared pool区)的统计信息。

如果字段REQUEST_FAILURES >= 0并且字段LAST_FAILURE_SIZE < _SHARED_POOL_RESERVED_MIN_ALLOC,可以考虑减小_SHARED_POOL_RESERVED_MIN_ALLOC,以使更多的对象能放到保留区中区(当然,你还需要观察字段MAX_USED_SPACE以确保保留区足够大)。如果还没有效果,就需要考虑增加shared_pool_size了。

碎片问题分析

Library cache和shared pool保留区的碎片也会导致4031错误的产生。

还是观察上面的视图,如果字段REQUEST_FAILURES > 0并且字段LAST_FAILURE_SIZE > _SHARED_POOL_RESERVED_MIN_ALLOC,就可以考虑增加_SHARED_POOL_RESERVED_MIN_ALLOC大小以减少放入保留区的对象,或者增加SHARED_POOL_RESERVED_SIZE和shared_pool_size(因为保留区是从shared pool中分配的)的大小。

 

此外,要注意有一个bug导致REQUEST_FAILURES在9.2.0.7之前所有版本和10.1.0.4之前的10g版本中统计的数据是错误的,这时可以观察最后一次4031报错信息中提示的无法分配的内存大小。

3.2.2.2.对large pool的分析

Large pool是在MTS、或并行查询、或备份恢复中存放某些大对象的。可以通过视图v$sgastat来观察large pool的使用情况和空闲情况。

而在MTS模式中,sort_area_retained_size是从large pool中分配的。因此也要检查和调整这个参数的大小,并找出产生大量sort的会话,调整语句,减少其中的sort操作。

MTS中,UGA也是从large pool中分配的,因此还需要观察UGA的使用情况。不过要注意一点的是,如果UGA无法从large pool获取到足够内存,会尝试从shared pool中去分配。

3.2.3.解决4031错误

根据4031产生的不同原因,采取相应办法解决问题。

3.2.3.1.bug导致的错误

有很多4031错误都是由于oracle bug引起的。因此,发生4031错误后,先检查是否你的系统的4031错误是否是由bug引起的。下面是已经发现的会引起4031错误的bug。相关信息可以根据bug号或note号到metalink上查找。

 

BUG

说明

修正版本

Bug 1397603

ORA-4031 由于缓存句柄导致的SGA永久内存泄漏

8172, 901

Bug 1640583

ORA-4031 due to leak / 由于查询计划中AND-EQUAL访问路径导致缓冲内存链争用,从而发生内存泄漏。

8171, 901

 Bug:1318267   (未公布)

如果设置了TIMED_STATISTICS可能导致INSERT AS SELECT无法被共享。

8171,  8200

 Bug:1193003 (未公布)

Oracle 8.1中,某些游标不共享。

8162, 8170, 901

Bug 2104071

ORA-4031 太多PIN导致shared pool消耗过大。

8174, 9013, 9201

Note 263791.1

许多与4031相关的错误在9205补丁集中修正。

9205

3.2.3.2.Sharedpool太小

大多数4031错误都是由shared pool不足导致的。可以从以下几个方面来考虑是否调整shared pool大小:

Library cache命中率

通过以下语句可以查出系统的library cache命中率:

SELECT SUM(PINS) "EXECUTIONS",

       SUM(RELOADS) "CACHE MISSES WHILE EXECUTING",

       1 - SUM(RELOADS)/SUM(PINS)

FROM V$LIBRARYCACHE;

如果命中率小于99%,就可以考虑增加shared pool以提高library cache的命中率。

计算shared pool的大小

以下语句可以查看shared pool的使用情况

select sum(bytes) from v$sgastat

where pool=‘shared pool‘

and name != ‘free memory‘;

专用服务模式下,以下语句查看cache在内存中的对象的大小,

select sum(sharable_mem)from v$db_object_cache;

专用服务模式下,以下语句查看SQL占用的内存大小,

select sum(sharable_mem)from v$sqlarea;

Oracle需要为保存每个打开的游标分配大概250字节的内存,以下语句可以计算这部分内存的占用情况,

select sum(250 * users_opening)from v$sqlarea;

 

此外,在我们文章的前面部分有多处提到了如何分析shared pool是否过大或过小,这里就不在赘述。

3.2.3.3.Sharedpool碎片

每当需要执行一个SQL或者PLSQL语句时,都需要从library cache中分配一块连续的空闲空间来解析语句。Oracle首先扫描shared pool查找空闲内存,如果没有发现大小正好合适的空闲chunk,就查找更大的chunk,如果找到比请求的大小更大的空闲chunk,则将它分裂,多余部分继续放到空闲列表中。这样就产生了碎片问题。系统经过长时间运行后,就会产生大量小的内存碎片。当请求分配一个较大的内存块时,尽管shared pool总空闲空间还很大,但是没有一个单独的连续空闲块能满足需要。这时,就可能产生4031错误。

如果检查发现shared_pool_size足够大,那4031错误一般就是由于碎片太多引起的。

如果4031是由碎片问题导致的,就需要弄清楚导致碎片的原因,采取措施,减少碎片的产生。以下是可能产生碎片的一些潜在因素:

o没有使用共享SQL

o过多的没有必要的解析调用(软解析);

o没有使用绑定变量。

以下表/视图、语句可以查询shared pool中没有共享的SQL

通过V$SQLAREA视图

前面我们介绍过这个视图,它可以查看到每一个SQL语句的相关信息。以下语句可以查出没有共享的语句,

SELECT substr(sql_text,1,40)"SQL",

count(*) ,

sum(executions) "TotExecs"

FROM v$sqlarea

WHERE executions < 5 –-语句执行次数

GROUP BY substr(sql_text,1,40)

HAVING count(*) > 30 –-所有未共享的语句的总的执行次数

ORDER BY 2;

X$KSMLRU

这张表保存了对shared pool的分配所导致的sharedpool中的对象被清出的记录。可以通过它来查找是什么导致了大的shared pool分配请求。

如果有许多对象定期会被从shared pool中被清出,会导致响应时间太长和library cache latch争用问题。

不过要注意一点,每当查询过表X$KSMLRU后,它的内容就会被删除。因此,最好将查出的数据保存在一个临时的表中。以下语句查询X$KSMLRU中的内容,

SELECT * FROM X$KSMLRU WHEREksmlrsiz > 0;

X$KSMSP

从这张表中可以查到当前分配了多少空闲空间,这对于分析碎片问题很有帮助。一些语句可以查询shared pool的空闲列表中chunk的统计信息,

select ‘0 (<140)‘ BUCKET,KSMCHCLS, KSMCHIDX, 10*trunc(KSMCHSIZ/10) "From",

count(*) "Count", max(KSMCHSIZ) "Biggest",

trunc(avg(KSMCHSIZ)) "AvgSize",trunc(sum(KSMCHSIZ)) "Total"

from x$ksmsp

where KSMCHSIZ<140

and KSMCHCLS=‘free‘

group by KSMCHCLS, KSMCHIDX,10*trunc(KSMCHSIZ/10)

UNION ALL

select ‘1 (140-267)‘ BUCKET,KSMCHCLS, KSMCHIDX,20*trunc(KSMCHSIZ/20) ,

count(*) , max(KSMCHSIZ),

trunc(avg(KSMCHSIZ)) "AvgSize",trunc(sum(KSMCHSIZ)) "Total"

from x$ksmsp

where KSMCHSIZ between 140and 267

and KSMCHCLS=‘free‘

group by KSMCHCLS, KSMCHIDX,20*trunc(KSMCHSIZ/20)

UNION ALL

select ‘2 (268-523)‘ BUCKET,KSMCHCLS, KSMCHIDX, 50*trunc(KSMCHSIZ/50) ,

count(*) , max(KSMCHSIZ),

trunc(avg(KSMCHSIZ)) "AvgSize",trunc(sum(KSMCHSIZ)) "Total"

from x$ksmsp

where KSMCHSIZ between 268and 523

and KSMCHCLS=‘free‘

group by KSMCHCLS, KSMCHIDX,50*trunc(KSMCHSIZ/50)

UNION ALL

select ‘3-5 (524-4107)‘ BUCKET,KSMCHCLS, KSMCHIDX, 500*trunc(KSMCHSIZ/500) ,

count(*) , max(KSMCHSIZ),

trunc(avg(KSMCHSIZ)) "AvgSize",trunc(sum(KSMCHSIZ)) "Total"

from x$ksmsp

where KSMCHSIZ between 524and 4107

and KSMCHCLS=‘free‘

group by KSMCHCLS, KSMCHIDX,500*trunc(KSMCHSIZ/500)

UNION ALL

select ‘6+ (4108+)‘ BUCKET,KSMCHCLS, KSMCHIDX, 1000*trunc(KSMCHSIZ/1000) ,

count(*) , max(KSMCHSIZ),

trunc(avg(KSMCHSIZ)) "AvgSize",trunc(sum(KSMCHSIZ)) "Total"

from x$ksmsp

where KSMCHSIZ >= 4108

and KSMCHCLS=‘free‘

group by KSMCHCLS, KSMCHIDX,1000*trunc(KSMCHSIZ/1000);

 

如果使用ORADEBUG将shared pool信息dump出来,就会发现这个查询结果和trace文件中空闲列表信息一致。

如果以上查询结果显示大多数空闲chunk都在bucket比较小的空闲列表中,则说明系统存在碎片问题。

3.2.3.4.编译java代码导致的错误

当编译java(用loadjava或deployjb)代码时产生了4031错误,错误信息一般如下:

A SQL exception occurredwhile compiling: :

ORA-04031: unable to allocatebytes of shared memory ("shared pool","unknown object","joxlod:init h", "JOX: ioc_allocate_pal")

这里提示时shared pool不足,其实是错误,实际应该是javapool不足导致的。解决方法将JAVA_POOL_SIZE加大,然后重启实例。

3.2.3.5.Largepool导致的错误

Large pool是在MTS、或并行查询、或备份恢复中存放某些大对象的。但和shared pool中的保留区(用于存放shared pool的大对象)不同,large pool是没有LRU链表的,而后者使用的是shared pool的LRU链表。

在large pool中的对象永远不会被清出的,因此不存在碎片问题。当由于large pool不足导致4031错误时,可以先通过v$sgastat查看large pool的使用情况,

SELECT pool,name,bytes FROMv$sgastat where pool = ‘large pool‘;

或者做一个dump,看看large pool中空闲chunk的大小情况。

进入large pool的大小条件是由参数LARGE_POOL_MIN_ALLOC决定的,根据以上信息,可以适当调整LARGE_POOL_MIN_ALLOC的大小。

Large pool的大小是由LARGE_POOL_SIZE控制的,因此当large pool空间不足时,可以调整这个参数。

3.2.4.SGA内存自动管理

10g以后,Oracle提供了一个非常有用的特性,即SGA内存自动管理。通过设置SGA_TARGET可以指定总的SGA大小,而无需固定每个区的大小。这就是说,当分配shared pool或large pool时,只要SGA区足够大,就能获取到足够内存,因而可以大大减少4031错误发生的几率。

3.2.5.FLUSHSHARED POOL

使用绑定变量是解决shared pool碎片的最好方法。此外,9i以后,可以设置CURSOR_SHARING为FORCE,强行将没有使用绑定变量的语句使用绑定变量,从而共享SQL游标。当采用以上措施后,碎片问题并不会马上消失,并可能还会长时间存在。这时,可以考虑flush shared pool,将内存碎片结合起来。但是,在做flush之前,要考虑以下问题。

Flush会将所有没有使用的游标从library cache中清除出去。因此,这些语句在被再次调用时会被重新硬解析,从而提高CPU的占用率和latch争用;

如果应用没有使用绑定变量,即使flush了shared pool以后,经过一段时间运行,仍然会出现大量碎片。因此,这种情况下,flush是没有必要的,需要先考虑优化应用系统;

如果shared pool非常大,flush操作可能会导致系统被hung住。

 

因此,如果要flush shared pool,需要在系统不忙的时候去做。Flush的语法为,

alter system flush shared_pool;

3.2.6.TRACE4031错误

如果问题比较复杂(比如由于内存泄漏导致),或者你不幸遇上了oracle的bug,这时就需要考虑设置4031事件来trace并dump出相关内存信息。

以下语句在整个系统设置4031事件,

SQL> alter system setevents ‘4031 trace name errorstack level 3‘;

 

SQL> alter system setevents ‘4031 trace name HEAPDUMP level 3‘;

这个事件也可以在会话中设置,只要将以上语句中的“system”改为“session”就行了。

然后将dump出来的trace文件发给oracle吧。

不过注意一点,9205以后就无需设置这个事件了,因为一旦发生4031错误时,oracle会自动dump出trace文件。

4.Dump内存解析

下面以shared pool为例,解释一下dump出来的内存结构。

SQL> conn sys/sys as sysdba

Connected.

SQL> oradebug setmypid

Statement processed.

SQL>  oradebug dump heapdump 2

Statement processed.

SQL>

 

以下时trace文件的内容,我们分别解释各个部分:

 

Dump file c:\oracle\product\10.2.0\admin\fuyuncat\udump\fuyuncat_ora_4032.trc

Tue Jul 11 16:03:26 2006

ORACLE V10.2.0.1.0 - Productionvsnsta=0

vsnsql=14 vsnxtr=3

Oracle Database 10g EnterpriseEdition Release 10.2.0.1.0 - Production

With the Partitioning, OLAPand Data Mining options

Windows XP Version V5.1 ServicePack 2

CPU                 : 2 - type 586

Process Affinity    : 0x00000000

Memory (Avail/Total): Ph:885M/2039M,Ph+PgF:2702M/3890M, VA:1590M/2047M

Instance name: fuyuncat

 

Redo thread mounted by thisinstance: 1

 

Oracle process number: 18

 

Windows thread id: 4032,image: ORACLE.EXE (SHAD)

 

 

*** SERVICE NAME:(SYS$USERS)2006-07-11 16:03:26.322

*** SESSION ID:(159.7) 2006-07-1116:03:26.322

这部分是关于trace文件的基本信息,oracle版本、资源情况、用户和会话等。

 

KGH Latch Directory Information

ldir state: 2  next slot: 75

Slot [  1] Latch: 03C3D280  Index: 1 Flags:  3  State: 2 next:  00000000

Slot [  2] Latch: 1EC9D4B0  Index: 1 Flags:  3  State: 2 next:  00000000

Slot [  3] Latch: 1EC9D540  Index: 1 Flags:  3  State: 2 next:  00000000

Slot [  4] Latch: 03C3E100  Index: 1 Flags:  3  State: 2 next:  00000001

Slot [  5] Latch: 1ED65CE4  Index: 1 Flags:  3  State: 2 next:  00000000

Slot [  6] Latch: 1ED65F14  Index: 1 Flags:  3  State: 2 next:  00000000

... ...

这部分记录的是shared pool中的latch信息。每个latch的具体信息可以通过视图V$LATCH、V$LATCH_PARENT、V$LATCH_CHILDREN或者表x$ksllt查出

 

******************************************************

HEAP DUMP heap name="sgaheap"  desc=03C38510

 extent sz=0x32c8 alt=108 het=32767 rec=9 flg=-126opc=0

 parent=00000000 owner=00000000 nex=00000000 xsz=0x10

******************************************************

这是堆dump信息的头部,heap name说明了内存所述的堆,shared pool是属于SGA区的,因此,这里是"sga heap";

extent sz记录的是所有扩展段的大小。

 

HEAP DUMP heap name="sgaheap(1,0)"  desc=04EC131C

 extent sz=0xfc4 alt=108 het=32767 rec=9 flg=-126opc=0

 parent=00000000 owner=00000000 nex=00000000 xsz=0x400000

EXTENT 0 addr=1CC00000

  Chunk 1cc00038 sz=       24 R-freeable  "reserved stoppe"

  Chunk 1cc00050 sz=   212888 R-free      "               "

  Chunk 1cc33fe8 sz=       24 R-freeable  "reserved stoppe"

  Chunk 1cc34000 sz=  3977544   perm      "perm           "  alo=3977544

  Chunk 1cfff148 sz=     3768   free      "               "

EXTENT 1 addr=1D000000

  Chunk 1d000038 sz=       24 R-freeable  "reserved stoppe"

  Chunk 1d000050 sz=   212888 R-free      "               "

  Chunk 1d033fe8 sz=       24 R-freeable  "reserved stoppe"

  Chunk 1d034000 sz=  2097168   perm      "perm           "  alo=2097168

这部分信息是trace文件中的主要部分,它详细记录了sharedpool中各个chunk的信息。

首先看它的头部信息,注意到这里heap name是"sgaheap(1,0)"。这是什么意思呢?我们前面提到,oracle 10g会将shared pool分为几个区来管理,这里就是其中的一个区。共有4个区。通过表X$KGHLU可以看到对应的LRU链表。

EXTENT 0 addr=1CC00000

这一行说明下面的chunk都属于这个扩展段(extent),0是它的编号,addr是它的起始地址。

  Chunk 1cc00038 sz=       24 R-freeable  "reserved stoppe"

这是一个chunk的信息,sz是这个chunk的大小(24字节)。R-freeable是这个chunk的状态,"reserved stoppe"是这个chunk的用途。Chunk有4种可能状态,以下是这四种状态的含义:

free:即空闲chunk,可以随时分配给适合大小的请求;

freeable:这种状态的chunk表示它当前正在被使用,但是这种使用是短期的,比如在一次调用中或者一个会话中,会话或者调用解释就可以被释放出来。这种状态的chunk是不放在LRU链表中的,一旦使用结束,自动成为free状态,放到空闲列表中;

recreatable:这种状态的chunk正在被使用,但是它所包含的对象是可以被暂时移走、重建,比如解析过的语句。它是被LRU链表管理的。

permanent:顾名思义,这种状态的chunk所包含的对象是永远不会被释放的。即使flush shared pool也不会释放。

我们注意到,这里还有一些状态是有前缀“R-”的。带有这种前缀的chunk说明是shared pool中的保留区的chunk。

 

Total heap size    = 41942480

最后是这一shared pool区的总的大小。

 

FREE LISTS:

 Bucket 0 size=16

 Bucket 1 size=20

  Chunk 166ed050 sz=       20   free      "               "

  Chunk 167de068 sz=       20   free      "               "

  Chunk 164b9c10 sz=       20   free      "               "

  Chunk 1f2776f8 sz=       20   free      "               "

接下来便是这个shared pool区的空闲列表。Bucket是一个空闲列表的范围,例如Bucket 1,它的最小值是上一个Bucket的最大值,即16,最大值为20。Bucket下面是空闲列表中chunk,后面的信息和前面解释chunk的信息一样,8位的16进制数字是它的地址;sz是chunk的大小;free是chunk的状态,因为是空闲列表中的chunk,这里只有一个状态;最后是chunk的用途,因为都是free,所以肯定为空。

 

Total free space   =  1787936

最后是这块shared pool区中空闲chunk的总的大小。

 

RESERVED FREE LISTS:

 Reserved bucket 0 size=16

 Reserved bucket 1 size=4400

 Reserved bucket 2 size=8204

 Reserved bucket 3 size=8460

 Reserved bucket 4 size=8464

 Reserved bucket 5 size=8468

 Reserved bucket 6 size=8472

 Reserved bucket 7 size=9296

 Reserved bucket 8 size=9300

 Reserved bucket 9 size=12320

 Reserved bucket 10 size=12324

 Reserved bucket 11 size=16396

 Reserved bucket 12 size=32780

 Reserved bucket 13 size=65548

  Chunk 1b800050 sz=   212888 R-free      "               "

  Chunk 16c00050 sz=   212888 R-free      "               "

  Chunk 1ac00050 sz=   212888 R-free      "               "

Total reserved free space   =   638664

Shared pool的普通区的空闲列表下面就是关于这块shared pool区中保留区的空闲列表的描述,其中除了在名字上bucket前面都有一个Reserved标识,和状态前面有“R-”前缀外,含义和普通空闲列表相同。

 

UNPINNED RECREATABLE CHUNKS(lru first):

  Chunk 1aee99c0 sz=     4096   recreate  "sql area       " latch=1D8BDD48

  Chunk 1ae4aeec sz=     4096   recreate  "sql area       " latch=1D8BDDB0

... ...

SEPARATOR

  Chunk 166e8384 sz=      540   recreate  "KQR PO         " latch=1DD7F138

  Chunk 1f333a5c sz=      284   recreate  "KQR PO         " latch=1DC7DFC8

  Chunk 166e9340 sz=      540   recreate  "KQR PO         " latch=1DE00A70

  Chunk 1f0fe058 sz=      284   recreate  "KQR PO         " latch=1DC7DFC8

  Chunk 1f2116b4 sz=      540   recreate  "KQR PO         " latch=1DE81910

  Chunk 1f21127c sz=      540   recreate  "KQR PO         " latch=1DE81910

... ...

Unpinned space     =  1611488  rcr=645 trn=864

空闲列表后面就是LRU链表了。LRU链表不是按照大小分的,因而没有Bucket。它的chunk是按照最近最少使用的顺序排列。其中chunk的信息和前面解释的一样。但是要注意一点,因为LRU链表中的chunk都是使用的,因为每个chunk根据用途不同,都会有一个latch来保护,Chunk信息最后便是latch的地址。

注意,我们前面提到,shared pool中是有两种LRU链表的,一种循环LRU链表;另外一种是暂时LRU链表。在这里LRU信息中前面部分是循环LRU链表,SEPARATOR后面部分是暂时LRU链表信息。

最后是LRU链表中chunk的总的大小,rcr是循环LRU链表中的chunk数,trn是暂时LRU链表中的chunk数。

此外,有一点提示,如果是有多个shared pool区,第一个区是不含LRU链表信息的。

 

PERMANENT CHUNKS:

  Chunk 1d234010 sz=  1884144   perm      "perm           "  alo=1728440

  Chunk 1cc34000 sz=  3977544   perm      "perm           "  alo=3977544

  Chunk 1d034000 sz=  2097168   perm      "perm           "  alo=2097168

  Chunk 1d434000 sz=  3117112   perm      "perm           "  alo=3117112

... ...

  Chunk 1f434000 sz=  3917704   perm      "perm           "  alo=3917704

Permanent space    = 38937696

最后是永久chunk的信息。Chunk部分解释和前面一致。alo表示已经分配的大小。

如果有多个shared pool区,永久chunk信息则只存在于第一个shared pool区。

all about Oracle memory - 错误处理

上一篇:DB2 runstats和reorg操作


下一篇:各数据库导入/导出Access教程--图解