共享池内存三维

网友投稿 875 2022-10-30

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

共享池内存三维

共享池是ORACLE数据库的核心内存

内容维度

SGA中的共享池由库缓存(Library Cache)、字典缓存(Dictionary Cache)、用于并行执行消息的缓冲以及控制结构组成。另外还有队列锁资源和RAC里面的资源信息

1.2.1 库缓存(Library Cache)

Library Cache中包括共享SQL区(Shared SQL Areas)、PL/SQL存储过程以及控制结构(如锁、库缓存句柄)。

任何用户都可以访问共享SQL区(可以通过v$sqlarea访问,随后会介绍这个重要视图)。因此库缓存存在于SGA的共享池中。

1) 共享SQL区和私有SQL区

Oracle会为每一条SQL语句运行(每运行一条语句Oracle都会打开一个游标)提供一个共享SQL区(Shared SQL Areas)和私有SQL区(Private SQL Areas属于PGA)。当发现两个(或多个)用户都在运行同一SQL语句时,Oracle会重新组织SQL区,使这些用户能重用共享SQL区。但他们还会在私有SQL区中保存一份这条SQL语句的拷贝。

一个共享SQL区中保存了一条语句的解析树和查询计划。在多用户系统中,Oracle通过为SQL语句使用同一共享SQL区多次运行来节省内存。

当一条新的SQL语句被解析时,Oracle从共享池中分配一块内存来存储共享SQL区。这块内存的大小与这条语句的复杂性相关。如果Shared Pool不够空间分配给共享SQL区,Oracle将释放从LRU链表中查找到最近最少使用的内存块,直到有足够空间给新的语句的共享SQL区。如果Oracle释放的是一个共享SQL区的内存,那么相应的语句在下次执行时需要再次解析并重新分配共享SQL区。而从解析语句到分配共享SQL区是一个比较消耗CPU的工程。这就是为什么我们提倡使用绑定变量的原因了。在没有使用绑定变量时,语句中的变量的数值不同,oracle就视为一条新的语句(9i后可以通过cursor_sharing来控制),重复上面的解析、内存分配的动作,将大大消耗系统资源,降低系统性能。

2) PL/SQL程序单元

Oracle对于PL/SQL程序单元(存储过程、函数、包、匿名PL/SQL块和触发器)的处理过程和对单个的SQL语句的处理过程相似。它会分配一个共享区来存储被解析、编译过的程序单元。同时分配一个私有区域来存放运行程序单元的会话所指定的程序单元的参数值(包括本地变量、全局变量和包变量——这也叫做包的实例化)和用于执行程序所需的内存。如果多个用户运行同一个程序单元,则他们共享同一个共享区域,并且各自保持一份私有区域,用于用户会话中指定的变量值。

而一个PL/SQL程序单元中的每条单个SQL语句的处理过程则和上面描述的SQL语句的处理过程相同。要注意一点,尽管这些语句是从PL/SQL程序单元中来的,但是Oracle还是会为这些语句分配一块共享SQL区,同时为每个用户分配一个相应的私有SQL区。

1.2.2 字典缓存(Dictionary Cache)

数据字典是有关于数据库的参考信息、数据库的结构信息和数据库中的用户信息的一组表和视图的集合,如我们常用到的V$视图、DBA_视图都属于数据字典。在SQL语句解析的过程中,Oracle可以非常迅速的访问(如果需要的话)这些数据字典,在SQL Trace中,这种对数据字典的访问就被统计为回调(recursive calls)。

因为Oracle对数据字典访问如此频繁,因此内存中有两处地方被专门用于存放数据字典。一个地方就是数据字典缓存(Data Dictionary Cache)。数据字典缓存也被称为行缓存(Row Cache),因为它是以记录行为单元存储数据的,而不像Buffer Cache是以数据块为单元存储数据。内存中另外一个存储数据字典的地方是库缓存。所有Oracle的用户都可以访问这两个地方以获取数据字典信息。

LIBRARY CACHE 里面存放如下东西,基本上都是代码

SYS@anqing2(rac2)> select namespace from v$librarycache;

NAMESPACE

---------------

SQL AREA

TABLE/PROCEDURE

BODY

TRIGGER

INDEX

CLUSTER

OBJECT

PIPE

Java SOURCE

Java RESOURCE

JAVA DATA

在AWR 里有关Library Cache Activity 的统计信息:

子共享池维度

为了提高并发性 Shared Pool能被分成7个子池,分别被不同的latch

(latch数最大为7,可以通过隐含参数_kghdsidx_count设置)保护。

表x$kghlu可以查看shared pool中的LRU列表。当满足以下条件之一时,shared pool会分为多个区,分别有不同的LRU链表管理:

1)在10g之前版本,如果shared pool大于128M、CPU数量大于4;

从Oracle 9i开始,Shared Pool可以被分割为多个子缓冲池(SubPool)进行管理,以提高并发性,减少竞争。Shared Pool的每个SubPool可以被看作是一个Mini Shared Pool,拥有自己独立的Free List、内存结构以及LRU List、shared pool latch。同时Oracle提供多个Latch对各个子缓冲池进行管理,从而避免单个Latch的竞争(Shared Pool Reserved Area同样进行分割管理)。从10G开始,每个SubPool由4个SUB PARTITION组成。

SubPool的个数和大小

每四个CPU分配一个SubPool,最多可以有7个。Shared Pool Latch也就从原来的一个增加到现在的7个。在Oracle 9i中,每个SubPool至少为128MB。10G-10.2.0.3,每个SubPool至少为256MB 10.2.0.3之后,最少为512M。

SubPool缺点:

从ORACL 10G开始,ORACLE进程在某个SubPool中请求内存失败,会到下一个SubPool中请求---过小的SubPool碎片问题可能更严重--ORA-4031出现机率更大。过多的SubPool还会带来更高的管理协调成本。比如以下错误就是与SubPool相关:ORA-04031: unable to allocate 4216 bytes of shared memory("shared pool","unknown object","sga heap(2,0)","library cache")

第三维度 内存维度

SELECT KSMCHCLS CLASS,

COUNT (KSMCHCLS) NUM,

SUM (KSMCHSIZ) SIZ,

TO_CHAR ( ( (SUM (KSMCHSIZ) COUNT (KSMCHCLS) 1024)), '999,999.00')

|| 'k'

"AVG SIZE"

FROM X$KSMSP

GROUP BY KSMCHCLS;

这个图说明是 共享池的内存属性,该内存也是以块为主分配,块的大小不确定,有大有小没有固定大小,不像BUFFER样 标准8K,或者其他的4,16,32KB。

内存分配根据需要对象的大小来拆分原来的大内存块。最后把内存撕裂变碎!

sys@DB> desc x$ksmsp

Name                         Type

------------------------  ----------------

ADDR                       RAW(8)

INDX                         NUMBER

INST_ID                    NUMBER

KSMCHIDX               NUMBER

KSMCHDUR             NUMBER

KSMCHCOM            VARCHAR2(16)

KSMCHPTR             RAW(8)

KSMCHSIZ              NUMBER

KSMCHCLS             VARCHAR2(8)

KSMCHTYP             NUMBER

KSMCHPAR             RAW(8)

这里需要关注一下以下几个字段。

⑴ ksmchcom 是注释字段,每个内存块被分配以后,注释会添加在该字段中。

⑵ ksmchsiz 代表块大小。

⑶ ksmchcls 列代表类型,主要有4类,具体说明如下:

·free:即Free Chunks,不包含任何对象的Chunk,可以不受限制的被自由分配。

·recr:即Recreatable Chunks,包含可以被临时移出内存的对象,在需要的时候,这个对象可以被重新创建。例如,许多存储共享SQL代码的内存都是可以重建的。

·freeable:即Freeable Chunks,包含session周期或调用的对象,随后可以被释放。这部分内存有时候可以全部或部分提前释放。但是注意,由于某些对象是中间过程产生的,这些对象不能临时被移出内存(因为不可重建)。

·perm:即Permanent Memory Chunks,包含永久对象,通常不能独立释放。

x$ksmss可以获得各个sub pool中空间信息

主要字段:

ksmdsidx:=0:表示内部使用内存   =1:表示sub pool

SQL>

select ksmdsidx sub_pool,sum(ksmsslen) bytes

from x$ksmss

where ksmsslen>0

group by ksmdsidx

order by sub_pool;

SUB_POOL BYTES

---------- ----------

1 1509950680

2 1543505304

3 4206462328

4 1577059984

5 1610618352

6 1442841952

7 1543505736

x$kghlu可以查看各子池的chunk使用情况

主要字段:

kghlushrpool:=1: shared pool subpools  =0: java pool

KGHLUIDX: sub-pool

KGHLUDUR:sub-sub-pool

kghlurcr:recurrent chunks

kghlutrn:transient chunks

kghlufsh:flushed chunks

kghluops:pins and releases chunks

kghlunfu:ora-4031 chunks

kghlunfs:last error chunk size

SQL>

select INDX,INST_ID,KGHLUIDX,KGHLUDUR,KGHLUNFU

from x$kghlu

where KGHLUSHRPOOL=1;

INDX  INST_ID KGHLUIDX KGHLUDUR KGHLUNFU

------- ---------- ---------- ---------- ------------ ----------

0                   1          7            0         5851

1                   1          6            0         63070

2                   1          5             0         71666

3                   1          4             0         9528

4                   1          3             0         69590

5                   1          2             0         6186

6                  1           1             0         62860

SELECT ksmchidx as SubPool,

'sga heap(' || ksmchidx || ',0)' as sga_heap,

ksmchcom as chunkcomment,

DECODE (ROUND (ksmchsiz 1000),0, '0-1K', 1, '1-2K',2, '2-3K',3, '3-4K',4, '4-5K', 5, '5-6k',6, '6-7k', 7, '7-8k',8, '8-9k',9, '9-10k', '> 10K') as SizeType,

COUNT (*) as block_num,

ksmchcls as status,

SUM (ksmchsiz) as BYTES

FROM x$ksmsp

WHERE ksmchcom = 'free memory'

GROUP BY ksmchidx, ksmchcls, 'sga heap(' || ksmchidx || ',0)',ksmchcom, ksmchcls,

DECODE (ROUND (ksmchsiz 1000),0, '0-1K', 1, '1-2K',2, '2-3K',3, '3-4K',4, '4-5K', 5, '5-6k',6, '6-7k', 7, '7-8k',8, '8-9k',9, '9-10k', '> 10K' )

order by SubPool,SizeType,block_num;

当这个三维度共同组成共享池的立体地图时候,总是会发生内存碎片,内存不够分之类的情况。因此我们需要保留一定的内存为了将来!

保留共享池

如果Oracle解析一个 PL/SQL程序单元,也需要从共享池中分配内存给这些程序单元对象。由于这些对象本一般比较大(如包),所以分配的内存空间也相对较大。系统经过长时间运行后,共享池可能存在大量内存碎片,导致无法满足对于大块内存段的分配。

为了使有足够空间缓存大程序块,Oracle专门从共享池内置出一块区域来来分配内存保持这些大块。这个保留共享池的默认大小是共享池的5%。它的大小也可以通过参数SHARED_POOL_RESERVED_SIZE来调整。保留区是从共享池中分配,不是直接从SGA中分配的,它是共享池的保留部分,用于存储大块段。

Shared Pool中内存大于5000字节的大段就会被存放在共享池的保留部分。而这个大小限制是通过隐含参数_SHARED_POOL_RESERVED_MIN_ALLOC来设定的(如前面所说,隐含参数不要去修改它)。除了在实例启动过程中,所有小于这个数的内存段永远都不会放到保留部分中,而大于这个值的大内存段也永远不会存放到非保留区中,即使共享池的空间不够用的情况下也是如此。

保留区的空闲内存也不会被包含在普通共享池的空闲列表中。它会维护一个单独的空闲列表。保留池也不会在它的LRU列表中存放可重建(Recreatable关于内存段的各种状态我们在后面的内容中再介绍)段。当释放普通共享池空闲列表上的内存时是不会清除这些大段的,同样,在释放保留池的空闲列表上的大内存段时也不会清除普通共享池中内存。

通过视图V$SHARED_POOL_RESERVED可以查到保留池的统计信息。其中字段REQUEST_MISSES记录了没有立即从空闲列表中得到可用的大内存段请求次数。这个值要为0。因为保留区必须要有足够个空闲内存来适应那些短期的内存请求,而无需将那些需要长期cache住的没被pin住的可重建的段清除。否则就需要考虑增大SHARED_POOL_RESERVED_SIZE了。

可以通过观察视图V$SHARED_POOL_RESERVED的MAX_USED_SPACE字段来判断保留池的大小是否合适。大多数情况下,你会观察到保留池是很少被使用的,也就是说5%的保留池空间可能有些浪费。但这需要经过长期观察来决定是否需要调整保留池大小。

保留区使用shared pool的LRU链表来管理内存块,但是在做扫描时,相互是不受影响的。例如,内存管理器扫描shared pool的LRU链表,清出空间以分配给一个小于5000字节的内存请求,是不会清出保留区的内存块的,相反亦然。

将重要、常用对象保持(Keep)在共享池中

根据LRU算法,一些一段时间没有使用到的内存块会被情况释放。这就可能导致一些重要的对象(如一个含有大量通用算法函数的包、被cache的序列)被从内存中清除掉。这些对象可能只是间歇被使用,但是因为他们的处理过程复杂(不仅包本身重新分配内存、解析,还要检查里面的所有语句),要在内存中重建他们的代价非常大。

我们可以通过调用存储过程DBMS_SHARED_POOL.KEEP将这些对象保持在共享池中来降低这种风险。这个存储过程立即将对象及其从事对象载入library cache中,并将他们都标记为保持(Keeping)状态。对于这种对象,我们建议在实例启动时就Keep住,以减少内存碎片的几率。

有一种观点认为那些大对象(如包)是没有必要被Keep住的,因为他们会被保持在共享池的保留区(如前所述,这个区通常使用率很低),所以一般不可能被清出。这个观点是错误滴!因为大多数大对象实际上是被分为多个小的内存段被载入共享池的,因此根本不会因为对象的大小而受到特别的保护。

另外,也不要通过频繁调用某些对象以防止他们被从共享池中清出。如果共享池大小设置合理,在系统运行的高峰时期,LRU链表会相对较短,那些没有被pin住的对象会很快被清出,除非他们被keep住了。

1.2.6  关于Shared Pool的重要参数

1)  SHARED_POOL_SIZE

它指定了Shared Pool的大小。9i下,在32位系统中,这个参数的默认值是8M,而64位系统中的默认值位64M。

但是,在SGA中还存在一块叫内部SGA消耗(Internal SGA Overhead)的内存被放置在共享池中。在9i及之前版本,共享池的统计大小(通过v$sgastat视图统计)为SHARED_POOL_SIZE +内部SGA消耗大小。而10g以后,SHARED_POOL_SIZE就已经包含了这部分内存大小。因此在10g中,共享池的实际使用大小就是SHARED_POOL_SIZE -内部SGA消耗大小,这在配置共享池大小时需要考虑进去,否则,扶过SHARED_POOL_SIZE设置过小,在实例启动时就会报ORA-00371错误。

2) SHARED_POOL_RESERVED_SIZE

这个参数前面已经提到,指定了共享池中缓存大内存对象的保留区的大小。这里不再赘述。

3)  _SHARED_POOL_RESERVED_MIN_ALLOC

这个参数前面也已经介绍,设置了进入保留区的对象大小的阀值。

Shared Pool的大小由参数SHARED_POOL_SIZE决定。9i中,在32位系统下,这个参数的默认值是8M,而64位系统下的默认值位64M。最大为4G。

10g 以后可以通过SGA_TARGET 参数来自动调整。

对于Shared Pool的内存管理,是通过修正过的LRU算法表来实现的。

1.2.3 共享池的内存管理

通常来说,共享池是根据修正过的LRU算法来是否其中的对象(共享SQL区和数据自动记录行)的,否则这些对象就一直保持在共享池中。如果共享池需要为一个新对象分配内存,并且共享池中没有足够内存时,内存中那些不经常使用的对象就被释放掉。一个被许多会话使用过的共享池对象,即使最初创建它的进程已经结束,只要它是有用的,都会被修正过的LRU算法一直保持在共享池中。这样就使一个多用户的Oracle系统对SQL语句的处理和内存消耗最小。

注意,即使一个共享SQL区与一个打开的游标相关,但如果它长时间没有被使用,它还是可能会被从共享池中释放出来。而此时如果打开的游标还需要运行它的相关语句,Oracle就会重新解析语句,并分配新的共享SQL区。

当一条SQL语句被提交给Oracle执行,Oracle会自动执行以下的内存分配步骤:

1. Oracle检查共享池,看是否已经存在关于这条语句的共享SQL区。如果存在,这个共享SQL区就被用于执行这条语句。而如果不存在,Oracle就从共享池中分配一块新的共享SQL区给这条语句。同时,无论共享SQL区存在与否,Oracle都会为用户分配一块私有SQL区以保存这条语句相关信息(如变量值)。

2. Oracle为会话分配一个私有SQL区。私有SQL区的所在与会话的连接方式相关。

在以下情况下,Oracle也会将共享SQL区从共享池中释放出来:

1)当使用ANALYZE语句更新或删除表、簇或索引的统计信息时,所有与被分析对象相关的共享SQL区都被从共享池中释放掉。当下一次被释放掉的语句被执行时,又重新在一个新的共享SQL区中根据被更新过的统计信息重新解析。

2) 当对象结构被修改过后,与该对象相关的所有共SQL区都被标识为无效(invalid)。在下一次运行语句时再重新解析语句。

3)如果数据库的全局数据库名(Global Database Name)被修改了,共享池中的所有信息都会被清空掉。

4)DBA通过手工方式清空共享池:ALTER SYSTEM FLUSH SHARED_POOL;

部分SWAP 内存知识

Linux 64 页表,进程内存,大页

SGA内存

PGA内存

Linux_x86_64BIT内存管理与分布

欢迎关注,感谢留言,希望分享

上一篇:人工智能时代 中培Python课程堪称时代风向标
下一篇:人工智能+Python进驻中培 引爆行业“薪”高潮
相关文章

 发表评论

暂时没有评论,来抢沙发吧~