allaboutOraclememory-Oracle的内存管理(二)

2014-11-24 16:56:09 · 作者: · 浏览: 8
找空闲空间。它们的不同处就在于子堆可以通过分配新的扩展段(extent)来增长,而shared pool具有固定的扩展段数(10g引入SGA自动管理特性后,shared pool的扩展段数也是可变的)。为子堆分配新的扩展段受到扩展段大小的限制,因此会存在这样的可能,因为没有任何一个父堆可以分配一个所需最小扩展段大小的chunk导致在子堆中查找一个小的chunk失败(抛4031错误)。

为了减少内存错误,在10g中,引入了多个隐含参数对扩展段进行控制,

_bct_buffer_allocation_min_extents 每次buffer cache分配时的最小扩展段数(1)。

_compilation_call_heap_extent_size 编译调用时分配堆的扩展段的大小(16384)10gR2引入。

_kgl_fixed_extents library cache内存分配时是否使用固定的扩展段大小(TRUE),10gR2引入。

_mem_std_extent_size 固定扩展段大小的堆的标准扩展段大小(4096),10gR2引入。

_minimum_extents_to_shrink 当内存收缩时,收缩的最少扩展段数(1)

_total_large_extent_memory 分配大扩展段的内存数(0),10gR1引入,10gR2中已经废除。

_pga_large_extent_size(1048576)和_uga_cga_large_extent_size(262144)控制了当使用系统函数mmap()初始化时,PGA、UGA和CGA扩张段的最大大小。

2.1.3.内存分配颗粒Granule

在Oracle的内存分配和管理中,有一个重要的单位:Granule(颗粒)。granule是连续虚拟内存分配的单位。Granule的大小依赖于SGA的总的大小(即SGA_MAX_SIZE大小)。当SGA小于128M时,granule为4M,SGA大于128M时,granule为16M。

Buffer Cache、Shared Pool、Large Pool和Java Pool(在10g中,还包括Streams Pool、KEEP buffer cache、RECYCLE buffer cache、nK Buffer Cache、ASM Buffer Cache)的增长和收缩都是以granule为单位的。SGA的各个组件的大小增长、收缩情况可以通过视图v$sga_dynamic_components(这个视图在1.1.2中有介绍)来观察。

在实例启动时, Oracle先分配granule条目(Entry),使所有granule能支持到SGA_MAX_SIZE的空间大小。如果没有设置PRE_PAGE_SGA和LOCK_SGA,在实例启动时,每个组件请求它所需要的最少granule。

因此最小SGA(占用物理内存)是3个granule,包括:

o固定SGA(包括redo buffer)一个granule

oBuffer Cache一个granule

oShared Pool一个granule

我们可以通过“ALTER SYSTEM”命令来修改分配给各个组件的granule数。当DBA想要给组件增加granule时,需要考虑实例中是否还有足够的granule来分配给新增加的组件大小(即增大后,各个组件之和小于SGA_MAX_SIZE)。有一点要注意,ALERT SYSTEM指定的是新的组件大小,是内存的大小,不是granule数。而Oracle在分配内存时,会以granule为单位,如果新分配的大小不是granule大小的倍数,则会使用最接近且大于分配数的granule的倍数值。例如,Unix中,当granule为16M,新分配组件大小为120M(不是16的倍数),Oracle则会实际分配128M(16×8);32位windows下,SGA小于1G时granule是4M,大于1G时granule是8M。

执行ALERT SYSTEM扩展组件大小后,前台进程(即执行ALTERSYSTEM命令)的进程会将SGA中的可用的granule(按照扩展新增大小计算)先保留下来。当这些granule被保留后,前台进程将后续处理交给后台进程。后台进程负责将这些保留的granule加到指定的组件的granule列表中去。这就完成了一次对SGA组件的扩展。

Granule的默认大小是根据以上规则规定的,但也可以通过隐含参数_ksm_granule_size来修改(强烈不建议修改)。另外,隐含参数_ksmg_granule_locking_status可以设置内存分配是否强制按照granule为单位进行分配。

2.1.4.SGA内存

当一个Oracle实例启动后,主要的SGA区的大小一开始基于初始化参数计算得出。这些大小可以通过show sga显示(实例启动后也会显示出这些信息)。但是,在共享内存段分配之前,每个区(Area)的大小都只有大概一个内存页大小。当需要时,这些区被分为一些子区(sub-area),因此没有一个子区会大于操作系统所限制的共享内存段(UNIX下受SHMMAX限制)的大小。对于可变区,有一个操作系统规定的最小子区大小,因此可变区的大小是最小子区大小的倍数。

如果可能,Oracle会为整个SGA分配一个单独的共享内存段。然而,如果SGA大于操作系统限制的单个共享内存段的大小时,Oracle会使用最佳的算法来将所有子区组织在多个共享段中,并且不超过SGA最大大小的限制。

严重的页入/页出会导致很严重的系统性能问题。然而,大内存消耗导致的间断的页入/页出是没有影响的。大多数系统都有大量的非活动内存被page out而没有什么性能影响。但少量的页出也是有问题的,因为这会导致SGA中那些中度活性的页会经常page out。大多数操作系统提供了一个让Oracle锁住SGA(设置lock_sga参数为TRUE)到物理内存中的机制以防止page out。在某些操作系统中,oracle需要有特定的系统权限来使用这一特性。

当共享池分配了一个chunk,代码会返回给执行分配的函数一个注释。这些注释可以通过表X$KSMSP的字段KSMCHCOM查到。它们同时描述了这块内存分配的目的。如以下语句:

select ksmchcom, ksmchcls, ksmchsiz from x$ksmsp;

2.1.5.进程内存

进程包括程序代码(文本)、本地数据域(进程堆栈、进程堆【主要是PGA】和进程BSS【未初始化的全局数据】)和SGA。程序代码的大小由基本内核、内核、联机的网络情况以及所使用的操作系统决定的。SGA大小是由Oracle初始化参数决定的。而这两部分是共享。随着用户的增加,它们与单个Oracle服务进程的关系越来越小。它们是可以通过修改Oracle配置参数来改变的。

本地数据域中的堆栈是根据需要来增大、缩小的。然而,堆就不会释放内存了。堆的主要组成部分是PGA。而影响PGA的主要因素是sort_area_size(如果没有配置PGA_AGGREGATE_TARGET的话)。因此,非自动PGA内存管理模式下,可以通过控制sort_area_size来控制PGA的大小。

因此,总的来说,可以