一、保留区
没有被PIN住大对象的加载、老化将会使共享池产生碎片,Oracle想了个方法解决这个问题,它专门在共享池开辟一块区域,所有大小超过4400字节的对象,将在此专门开辟的区域中分配空间,这块区域被称为保留区。这样,让大对象和小对象分开存储,可以减少大对象的加载、老化以大量小对象产生的影响,并且可以减少小对象区域内的内存碎片。而且Oracle针对保留区设计了专门的内存管理算法,使得大对象可以更快速的加载。
你可以使用shared_pool_reserved_size参数设置此保留区的大小,默认情况下,保留区将被自动设置为共享池大小的5%。另外,保留区大小不能设置为超过共享池大小的一半,否则将会报出错误。通常情况下,保留区的大小保留默认值就行,我们一般不需要调节它。
关于进入保留区对象的大小,Oracle更不建议我们调节它。但有时4400这个值对我们的系统可能并不合适。假设经常4000字节左右(不到4400)的对象被加载到共享池中,三、四千字节的对象,已经是大对象了,并且这些大对象很少使用,这样将它们PIN在内存中有点浪费空间,不到4400的大小使得它们无法被加载到保留区,这些对象每次执行时的加载需要老化很多小对象,并且还很容易造成共享池的碎片。这时,我们可以调低4400这个限制值,比如我们可以将保留区的限制降到3500,这样可以让那些本来不能进入保留区的对象可以进入保留区。这不旦可以加快这些对象的加载速度,重要的是减少了它们对众多小对象的影响。我们可以通过V$DB_ OBJECT_CACHE观察对象在共享池中所占用的内存大小,如果发现上述情况,可以调低4400这个限制值。这个限制是用一个隐藏参数来设置的:_shared_pool_reserved_min_alloc。凡是参数名前带有下划线的,都被称为隐藏参数,这些隐藏参数不能通过Show parameter显示,我们可以使用我写的脚本Show_para.sql显示隐藏参数和它们的意义,此脚本的编写见本章末尾的附录部分。
有一个视图可以用来帮助调节保留区:V$SHARED_POOL_RESERVED,它有如下的列:
FREE_SPACE:保留区中自由空间的总和
AVG_FREE_SIZE:每个自由内存块的平均大小
FREE_COUNT:自由的内存块数量
MAX_FREE_SIZE:最大的自由内存块大小
USED_SPACE:保留区中已使用的空间大小
AVG_USED_SIZE:每个已经使用的内存块的平均大小
USED_COUNT:已使用的内存块数量
MAX_USED_SIZE:已使用的最大的内存块大小
REQUESTS:在保留区中搜索自由内存块的次数
REQUEST_MISSES:保留区中没有可以满足要求的内存块并开始在保留区中LRU链中刷新对象的次数
LAST_MISS_SIZE:最后一次出现REQUEST_MISSES时,所请求的空间大小
MAX_MISS_SIZE:最大一次出现REQUEST_MISSES时,所请求的空间大小
下面的列即使SHARED_POOL_RESERVED_SIZE没有被设置也是有效的:
REQUEST_FAILURES:无论保留区还是非保留区,没有可以满足要求的内存的次数(也就是ORA-4031错误发生的次数)
LAST_FAILURE_SIZE:最后一次REQUEST_FAILURES时所请求的内存大小
后三列相关DBMS_SHARED_POOL.ABORTED_REQUEST_THRESHOLD过程。
ABORTED_REQUEST_THRESHOLD:最小的超过DBMS_SHARED_POOL.ABORTED_REQUEST_THRESHOLD设置值的大小
ABORTED_REQUESTS:超过DBMS_SHARED_POOL.ABORTED_REQUEST_THRESHOLD的次数
LAST_ABORTED_SIZE:最后一次超过DBMS_SHARED_POOL.ABORTED_REQUEST_THRESHOLD时的大小。
注意,如果REQUEST_FAILURES大于0且持续增加时,说明用户要求大小为N的内存块,但共享池内已经没有大小超过N的内存块。当REQUEST_FAILURES增加的比较快时,用户的操作将会失败并收到著名的ORA-04031错误,就是“共享池内存不足”,通常还有一句“不能申请大于N字节的内存块”。
造成这种情况有三种原因,一是内存的确不足了,这个时候你要增加内存。二是共享池中还有内存,但都是小块,没有大小超过N字节的内存块以满足用户的请求,也就是说内存中有碎片了。关于共享池内存碎片的解决方法,我们马上就说。再来看第三种情况,三是共享池中还有内存,但因为保留区设置的不合理,用户要在普通区中请求内存(用户请求的内存大小未超过4400),而普通区中已经没有自由内存了,但保留区中还有很多空闲。或者情况相反,用户在保留区中请求内存,保留区内存已经不足,但普通区中仍有大量内存空余。
当4031错误出现时,你的情况是否属于第三种―――保留设置不合理,可以通过本节所介绍的视图得知。下面我们分别介绍一下普通区空间不足和保留区空间不足这两种情况的监测和解决:
(一) 、普通区内存空间不足:
REQUEST_FAILURES不为0且持续增加时,如果LAST_FAILURE_SIZE < _SHARED_POOL_RESERVED_MIN_ALLOC(进入保留区的对象最小大小限制),例如,_SHARED_POOL_RESERVED_MIN_ALLOC限制仍是默认值4400,而LAST_FAILURE_SIZE是3800,也就是最后一次用户请求内存失败时用户所请求的内存大小为3800字节。3800小于4400,这说明用户是在普通区中请求内存失败的。观察一下保留区内存是否充足,如果充足的话,可以将_SHARED_POOL_RESERVED_MIN_ALLOC设置的小于3800让用户的请求在保留区内分配,或才干脆减少保留区大小,这样普通区中空间自然就会多起来。那么,如果确定保留区中内存是否充足呢?可以通过下面这些列进行观察:
Ÿ FREE_SPACE:保留区中自由空间的总和
Ÿ AVG_FREE_SIZE:每个自由内存块的平均大小
Ÿ FREE_COUNT:自由的内存块数量
Ÿ MAX_FREE_SIZE:最大的自由内存块大小
Ÿ USED_SPACE:保留区中已使用的空间大小
Ÿ AVG_USED_SIZE:每个已经使用的内存块的平均大小
Ÿ USED_COUNT:已使用的内存块数量
Ÿ MAX_USED_SIZE:已使用的最大的内存块大小
如果FREE_SPACE显示的自由空间还有很多,就说明保留区中仍有大量空间,完全可以将_SHARED_POOL_RESERVED_MIN_ALLOC设置的小一些,或减少保留区所占内存。
如果保留区中空间也不是太足了,就需要检查共享池中是否碎片太多,如果不是碎片的问题,就只有增大共享池大小了。关于碎片我们马上就讨论。
(二) 、保留区空间不足
当REQUEST_FAILURES不为0且持续增加时,LAST_FAILURE_SIZE > _SHARED_POOL_RESERVED_MIN_ALLOC,就说明用户所请求的内存要在保留区中分配,而保留区这时的空间已经不足已满足用户的请求了。
这时我们可以加大_SHARED_POOL_RESERVED_MIN_ALLOC的限制值,减少进入保留区的对象数。将SHARED_POOL_RESERVED_SIZE参数的值设大一些,以增加保留区大小。当然,如果你的主机上仍有空余内存,也可以增大共享池内存大小。
二、共享池碎片
共享池内存不足的一个主要原因就是共享池碎片。我们先说解决这个问题的方法,很简单,就是使用如下的命令清空共享池:
alter system flush shared_pool;
这条语句也叫做刷新共享池。这条命令将大部分共享池的空间变为了刚启动数据库时的状态。也就是说它清空了大部分共享池中的数据,并且会将碎片进行合并。这条语句对系统的影响是非常大的,因此,不要轻易的使用。一定要在确定了共享池内存问题是因为碎片引起的时,才可以使用它。那么,如何确定共享池是否碎片过多呢。简单的方法是看V$SHARED_POOL_RESERVED视图中的LAST_FAILURE_SIZE列,或者看报出ORA-04031错误时的提示,“请求N字节的内存失败”。如果这个N是一个很小的值,假设只有80字节,也就是说共享池中空闲的内存块都不超过80字节。Oracle会将连续的内存块合并,即使在连续的内存块合并后,也没有了80字节的内存块。这说明共享池中已经有了碎片。或者,也可能是因为共享池内存不足了。要想进一步的判断,我们可以使用我写的脚本Show_sp.sql,它的编写见本章附录,下面是脚本的输出格式:
SQL> @?/sql/show_sp
KSMCHCOM size COUNT(*) STATUS BYTES
---------------- ----- ---------- -------- ----------
free memory 0-1K 356 free 39116
free memory 1-2K 60 free 53576
free memory 2-3K 7 free 14372
free memory 3-4K 8 free 25384
free memory 4-5K 40 free 158144
free memory 5-6k 1 free 5180
free memory 8-9k 1 free 8296
free memory > 10K 11 free 3382344
free memory > 10K 16 R-free 3406208
这个脚本依次显示了0-1K、1-2K、3-4K等等大小的自由内存块数量。通过这个视图我们可以了解到自由内存块的大小分布。我上面这个结果是数据库刚启动时的状态,我们可以看到大小在10K之上的大内存块还有很多。随着用户的操作,大的内存块被不断的切割、变小,大内存块可能会越来越少,也越来越小。如果出现我4031时,通过使用上面的脚本,观察到大小在2K之上的内存块已经被耗尽了,而0-1K,1-2K的内存块却有很多,这基本上就可以确定是碎片太多了。这时就可以通过刷新共享池来解决问题。
不过,有时的4031错误是非常严重的,严重到无论什么操作都无法执行了,对于这种4031错误,只有重启数据库了。
另外说明一点,保留区是不会有碎片的,因为Oracle对保留区内存管理算法进行了改进,所以保留区内不会有碎片。但保留区并不适合存放过小的对象。