oracle sga 之 shared pool
原文链接:ORACLE SGA之shared pool
shared pool
的内存块组成
shared pool
中主要的内存区域:free
、library cache
、row cache
为了确保共享池中共享数据的访问性能,共享池的每次内存分配都必须是连续的内存空间,经过一段时间的运行,共享池中会产生一些碎片,这些碎片分布在一些连续分配的空间之间。
共享池堆的内部结构
oracle
的内存空间分配是采用堆管理(HEAP
)的模式。比如SGA HEAP
、PGA HEAP
、HEAP TABLE
等都是堆内存管理。每个堆包含一个堆句柄
和一系列的内存扩展
,每个扩展又包含一系列连续的chunk
。内存申请者通过在堆上申请空间的模式来获得内存。
堆创建包含两个步骤
一是初始化堆的句柄
二是给堆分配空间
从 chunk
中分配空间的基本顺序如下
1).首先搜索
freelist
上是否存在可以释放的chunk
(在该区域查找的时候首先根据需要分配空间的大小,找到相应的bucket
,然后搜索整个链表,如果找到了大小相同的chunk
,那么就直接分配使用。如果找不到合适的chunk
,就会选择一个稍大的chunk
,分配一个和所需空间大小一致的chunk
,剩下的空间根据大小挂载到相应的bucket
链表上)。
2).如果没找到,就查找是否有
recreateable
的chunk
可以释放。释放已经使用的chunk
,需要用到LRU
链表。LRU
链表根据使用的频繁程度,通过一个双向链
来串联已经被分配的chunk
。如果在LRU
链上找到了可以释放的chunk
,就通知HEAP MANAGER
去释放,如果该chunk
是被锁住的,首先要解锁,然后才能释放。HEAP MANAGER
在释放内存时,会自动合并碎片。
3).如果此时还没有找到可以释放的
chunk
,就从父堆里分配空闲的空间。
4).如果父堆无法分配空间,就会报错。
free
空间
是一个一个的内存块,使用链(
chain
)将空闲内存块链起来,(每个链上所挂载的内存块大小是不一样的)。如:硬解析一个sql
语句,需要根据解析的sql语句和sql语句的执行计划,它所需要占用的实际内存空间,从相应的链上找空间存放。硬解析需要内存空间,根据实际大小的free
内存空间中的链中找到相应大小内存块使用,会产生小内存块(内存碎片
)。系统如果有大量硬解析的话。虽然free
里面还有很多空间,但是所有的空间都是小的。并不能使用。
SQL>
select * from v$sgastat where pool='shared pool' and name='free memory';
library cache空间
library cache
里面有很多链,链下挂有很多chunk
,但是chunk
里面都写了内容(sql
,sql
执行计划)。
根据什么把不同的chunk写上内存后挂在不同链上
把
sql
语句所有的字母转换成ASCII
码值,就成了数字,对这些数字经过几次运算,就是链的编号,这个sql
语句就挂到所对应的编号上。当再次执行sql
语句的时候,就会从对应编号的链上去找对应的chunk
。
SQL>
select * from v$sgastat where name='library cache';
数据字典缓存(row cache
)
数据字典缓存不是纯粹的数据字典表的缓存,数据字典缓存是经过组织的,用于数据库运行中
sql
解析、权限控制等用途的内部数据结构,是一种字典表的内存视图。如:在执行某个sql
的时候,为了sql
解析,需要访问一些字典表,从中获取一些数据,那么它会通过一些递归调用sql
来完成这些事情。首先需要将数据块从系统表空间中读取到DB cache
,然后从DB cache
中获得sql
所需要的行数据。为了减少递归sql
的执行开销,这些行数据被缓存在共享池中,这个缓存就是数据字典缓存。
SQL>
select * from v$sgastat where name='row cache';
执行一条之前为缓存的sql
语句,查看链表中chunk
数量的变化
SQL>
select count(*) from x$ksmsp;
COUNT(*)
36635
SQL>
select count(*) from dba_indexes;
–第一次执行发生硬解析,链上的chunk
数量将有所增加
COUNT(*)
2344
SQL> select count(*) from x$ksmsp;
COUNT(*)
36650
SQL>
alter system flush shared_pool;
–将shared pool
清空,之后第一次执行的所有DML
语句都将是硬解析
shared pool
中的保留池设置
如果共享池中碎片化变得十分严重,就会导致比较大的共享内存分配无法满足需求,
oracle
在共享池中设计了保留池.
保留池的设计目的是为了在共享池碎片化很严重的时候,还能够有一部分保留空间,用于较大的内存分配。可以通过参数shared_pool_reserved_size
来设置保留池的大小(由于oracle
的内存自动管理机制,一般情况下不需要手动设置)。
SQL> show parameter shared_pool_reserved_size;
NAME
TYPE
VALUE
shared_pool_reserved_size
big integer 6081740
保留池的使用条件
- 必须是在共享池的
freelist
中找不到足够大的chunk
- 分配的内存容量要大于
shared_pool_reserved_min_alloc
的设定值(从8i
开始该参数变为隐含参数,即shared_pool_reserved_min_alloc
,默认值为4400B
),只有大于该设定值的内存分配才被认为是大内存分配
。