Oracle的内存配置与oracle性能息息相关。关于内存的配置,是最影响Oracle性能的配置。内存还直接影响到其他两个重要资源的消耗:CPU和IO.
先看Oracle内存存储的主要内容是什么:
程序代码(PLSQL、Java);
关于已经连接的会话的信息,包括当前所有活动和非活动会话;
程序运行时必须的相关信息,例如查询计划;
Oracle进程之间共享的信息和相互交流的信息,例如锁;
那些被永久存储在外围存储介质上,被cache在内存中的数据(如redo log条目,数据块)。
每个Oracle数据库都是由Oracle Instance(实例)与数据库(数据文件,控制文件、重做日志文件)组成,其中所谓实例就是用户同数据库交互的媒介,用户通过于一个实例相连来操作数据库。而实例又是由统一的内存结构(SGA,PGA,UGA)和一批内存驻留进程组成。实例在操作系统中用ORACLE_SID来标识,在Oracle中用参数INSTANCE_NAME来标识, 它们两个的值是相同的。数据库启动时,系统首先在服务器内存中分配系统全局区(SGA), 构成了Oracle的内存结构,然后启动若干个常驻内存的操作系统进程,即组成了Oracle的 进程结构,内存区域和后台进程合称为一个Oracle实例。
一. SGA
SGA是一组为系统分配的共享的内存结构,可以包含一个数据库实例的数据或控制信息。如果多个用户连接到同一个数据库实例,在实例的SGA中,数据可以被多个用户共享。 当数据库实例启动时,SGA的内存被自动分配;当数据库实例关闭时,SGA内存被回收。 SGA是占用内存最大的一个区域,同时也是影响数据库性能的重要因素。
SGA区是可读写的。所有登录到实例的用户都能读取SGA中的信息,而在oracle做执行操作时,服务进程会将修改的信息写入SGA区。
SGA主要包括了以下的数据结构:
数据缓冲(Buffer Cache)
重做日志缓冲(Redo Log Buffer)
共享池(Shared Pool)
Java池(Java Pool)
大池(Large Pool)
流池(Streams Pool --- 10g以后才有)
数据字典缓存(Data Dictionary Cache)
其他信息(如数据库和实例的状态信息)
SQL> show sga
Total System Global Area 612368384 bytes
Fixed Size 1250428 bytes
Variable Size 192940932 bytes
Database Buffers 411041792 bytes
Redo Buffers 7135232 bytes
SGA 中的数据字典缓存 和其他信息 会被实例的后台进程所访问,它们在实例启动后就固定在SGA中了,而且不会改变,所以这部分又称为固定SGA(Fixed SGA)。这部分区域的大小一般小于100K。
Shared Pool、Java Pool、Large Pool和Streams Pool这几块内存区的大小是相应系统参数设置而改变的,所以有通称为可变SGA(Variable SGA)。
截图出自Oracle 11g 的架构图。 下载地址:http://download.csdn.net/source/2346700
通过下面的语句查询
SQL> show parameter sga
NAME TYPE VALUE
------------------------------------ ----------- -------
lock_sga boolean FALSE
pre_page_sga boolean FALSE
sga_max_size big integer 584M
sga_target big integer 584M
先对这几个参数做一下说明:
SQL> select name,value ,ISSYS_MODIFIABLE from v$parameter where name like 'sga%';
NAME VALUE ISSYS_MOD
--------------- --------------- ---------
sga_max_size 612368384 FALSE
sga_target 612368384 IMMEDIATE
如果ISSYS_MODIFIABLE 返回的是false,说明该参数无法用alter system语句动态修改,需要重启数据库。
所以sga_max_size 是不可以动态调整的。但是我们可以对sga_target 进行动态的调整。
SGA_MAX_SIZE:
SGA区包括了各种缓冲区和内存池,而大部分都可以通过特定的参数来指定他们的大小。但是,作为一个昂贵的资源,一个系统的物理内存大小是有限。尽管对于CPU的内存寻址来说,是无需关系实际的物理内存大小的,但是过多的使用虚拟内存导致page in/out,会大大影响系统的性能,甚至可能会导致系统crash。所以需要有一个参数来控制SGA使用虚拟内存的最大大小,这个参数就是SGA_MAX_SIZE。
当实例启动后,各个内存区只分配实例所需要的最小大小,在随后的运行过程中,再根据需要扩展他们的大小,而他们的总和大小受到了SGA_MAX_SIZE的限制。
当试图增加一个内存的大小,并且如果这个值导致所有内存区大小总和大于SGA_MAX_SIZE时,oracle会提示错误,不允许修改。
当然,如果在设置参数时,指定区域为spfile时(包括修改SGA_MAX_SIZE本身),是不会受到这个限制的。这样就可能出现这样的情况,在spfile中,SGA各个内存区设置大小总和大于SGA_MAX_SIZE。这时,oracle会如下处理:当实例再次启动时,如果发现SGA各个内存总和大于SGA_MAX_SIZE,它会将SGA_MAX_SIZE的值修改为SGA各个内存区总和的值。
SGA所分配的是虚拟内存,但是,在我们配置SGA时,一定要使整个SGA区都在物理内存中,否则,会导致SGA频繁的页入/页出,会极大影响系统性能。
对于OLTP系统,一般的建议是将SGA_MAX_SIZE 设为物理内存的60%,PGA 设为20%。 但是现在服务器内存是相当大的。 几百G的内存随处可见。60%也就是几百G内存。 显然这样也是不合适的。 所以要根据自己系统来设定设定这个值。这个也就所说的DBA的经验。 这是是需要经验的积累。
下表的几个数值供参考。
系统内存 | SGA_MAX_SIZE值 |
1G | 400-500M |
2G | 1G |
4G | 2500M |
8G | 5G |
SGA的实际大小可以通过以下公式估算:
SGA实际大小 = DB_CACHE_SIZE + DB_KEEP_CACHE_SIZE + DB_RECYCLE_CACHE_SIZE + DB_nk_CACHE_SIZE + SHARED_POOL_SIZE + LARGE_POOL_SIZE + JAVA_POOL_SIZE + STREAMS_POOL_SIZE(10g中的新内存池) + LOG_BUFFERS+11K(Redo Log Buffer的保护页) + 1MB + 16M(SGA内部内存消耗,适合于9i及之前版本)
PRE_PAGE_SGA:
oracle实例启动时,会只载入各个内存区最小的大小。而其他SGA内存只作为虚拟内存分配,只有当进程touch到相应的页时,才会置换到物理内存中。我们可以通过设置PRE_PAGE_SGA参数,让实例一启动后,所有SGA都分配到物理内存。
这个参数的默认值为FALSE,即不将全部SGA置入物理内存中。当设置为TRUE时,实例启动会将全部SGA置入物理内存中。它可以使实例启动达到它的最大性能状态,但是,启动时间也会更长(因为为了使所有SGA都置入物理内存中,oracle进程需要touch所有的SGA页)。
SQL> alter system set pre_page_sga=true scope=spfile;
LOCK_SGA
为了保证SGA都被锁定在物理内存中,而不必页入/页出,可以通过参数LOCK_SGA来控制。这个参数默认值为FALSE,当指定为TRUE时,可以将全部SGA都锁定在物理内存中。当然,有些系统不支持内存锁定,这个参数也就无效了。
SGA_TARGET
Oracle10g中引入的一个非常重要的参数。在10g之前,SGA的各个内存区的大小都需要通过各自的参数指定,并且都无法超过参数指定大小的值,尽管他们之和可能并没有达到SGA的最大限制。此外,一旦分配后,各个区的内存只能给本区使用,相互之间是不能共享的。拿SGA中两个最重要的内存区Buffer Cache和Shared Pool来说,它们两个对实例的性能影响最大,但是就有这样的矛盾存在:在内存资源有限的情况下,某些时候数据被cache的需求非常大,为了提高buffer hit,就需要增加Buffer Cache,但由于SGA有限,只能从其他区“抢”过来——如缩小Shared Pool,增加Buffer Cache;而有时又有大块的PLSQL代码被解析驻入内存中,导致Shared Pool不足,甚至出现4031错误,又需要扩大Shared Pool,这时可能又需要人为干预,从Buffer Cache中将内存夺回来。
10g 以后有了新特性:自动共享内存管理(Automatic Shared Memory Management ASMM)。而控制这一特性的,也就仅仅是这一个参数SGA_TARGE。设置这个参数后,就不需要为每个内存区来指定大小了。SGA_TARGET指定了SGA可以使用的最大内存大小,而SGA中各个内存的大小由Oracle自行控制,不需要人为指定。Oracle可以随时调节各个区域的大小,使之达到系统性能最佳状态的个最合理大小,并且控制他们之和在SGA_TARGET指定的值之内。一旦给SGA_TARGET指定值后(默认为0,即没有启动ASMM),就自动启动了ASMM特性。如果不设置SGA_TARGET,则自动共享内存管理功能被禁止。
设置了SGA_TARGET后,以下的SGA内存区就可以由ASMM来自动调整:
共享池(Shared Pool)
Java池(Java Pool)
大池(Large Pool)
数据缓存区(Buffer Cache)
流池(Streams Pool)
对于SGA_TARGET的限制,它的大小是不能超过SGA_MAX_SIZE的大小的。
要注意的是:当指定SGA_TARGET小于SGA_MAX_SIZE,实例重启后,SGA_MAX_SIZE就自动变为和SGA_TARGET一样的值了。
SGA_TARGET,它的值可以动态修改(在SGA_MAX_SIZE范围内)。在10g之前,如果需要修改SGA的大小(即修改SGA_MAX_SIZE的值)需要重启实例才能生效。当然,在10g中,修改SGA_MAX_SIZE的值还是需要重启的。但是有了SGA_TARGET后,可以将SGA_MAX_SIZE设置偏大,再根据实际需要调整SGA_TARGET的值(我个人不推荐频繁修改SGA的大小,SGA_TARGET在实例启动时设置好,以后不要再修改)。
SGA_TARGET带来一个重要的好处就是,能使SGA的利用率达到最佳,从而节省内存成本。因为ASMM启动后,Oracle会自动根据需要调整各个区域的大小,大大减少了某些区域内存紧张,而某些区域又有内存空闲的矛盾情况出现。这也同时大大降低了出现4031错误的几率。
1.1 Database Buffer Cache
Buffer Cache是SGA区中专门用于存放从数据文件中读取的的数据块拷贝的区域。Oracle进程如果发现需要访问的数据块已经在buffer cache中,就直接读写内存中的相应区域,而无需读取数据文件,从而大大提高性能(内存的读取效率是磁盘读取效率的14000倍)。Buffer cache对于所有oracle进程都是共享的,即能被所有oracle进程访问。
和Shared Pool一样,buffer cache被分为多个集合,这样能够大大降低多CPU系统中的争用问题。
1.1.1 Buffer cache的管理
Oracle对于buffer cache的管理,是通过两个重要的链表实现的:写链表和最近最少使用链表(the Least Recently Used LRU)。写链表所指向的是所有脏数据块缓存(即被进程修改过,但还没有被回写到数据文件中去的数据块,此时缓冲中的数据和数据文件中的数据不一致)。而LRU链表指向的是所有空闲的缓存、pin住的缓存以及还没有来的及移入写链表的脏缓存。空闲缓存中没有任何有用的数据,随时可以使用。而pin住的缓存是当前正在被访问的缓存。LRU链表的两端就分别叫做最近使用端(the Most Recently Used MRU)和最近最少使用端(LRU)。
1)Buffer cache的数据块访问
当一个Oracle进程访问一个缓存时,这个进程会将这块缓存移到LRU链表中的MRU。而当越来越多的缓冲块被移到MRU端,那些已经过时的脏缓冲(即数据改动已经被写入数据文件中,此时缓冲中的数据和数据文件中的数据已经一致)则被移到LRU链表中LRU端。
当一个Oracle用户进程第一次访问一个数据块时,它会先查找buffer cache中是否存在这个数据块的拷贝。如果发现这个数据块已经存在于buffer cache(即命中cache hit),它就直接读从内存中取该数据块。如果在buffer cache中没有发现该数据块(即未命中cache miss),它就需要先从数据文件中读取该数据块到buffer cache中,然后才访问该数据块。命中次数与进程读取次数之比就是我们一个衡量数据库性能的重要指标:buffer hit ratio(buffer命中率),可以通过以下语句获得自实例启动至今的buffer命中率:
SQL>select (1-(sum(decode(name, 'physical reads',value,0))/(sum(decode(name, 'db block gets',value,0))
+sum(decode(name,'consistent gets',value,0))))) * 100 "Hit Ratio" from v$sysstat;
Hit Ratio
----------
98.3471481
一个良好性能的系统,命中率一般保持在95%左右。
关于命中率,可以参考我的blog:Oracle 检查命中率的SQL
http://blog.csdn.net/tianlesoftware/archive/2009/10/16/4674153.aspx
上面提到,如果未命中(missed),则需要先将数据块读取到缓存中去。这时,oracle进程需要从空闲列表种找到一个适合大小的空闲缓存。如果空闲列表中没有适合大小的空闲buffer,它就会从LRU端开始查找LRU链表,直到找到一个可重用的缓存块或者达到最大查找块数限制。在查找过程中,如果进程找到一个脏缓存块,它将这个缓存块移到写链表中去,然后继续查找。当它找到一个空闲块后,就从磁盘中读取数据块到缓存块中,并将这个缓存块移到LRU链表的MRU端。
当有新的对象需要请求分配buffer时,会通过内存管理模块请求分配空闲的或者可重用的buffer。“free buffer requested”就是产生这种请求的次数;
当请求分配buffer时,已经没有适合大小的空闲buffer时,需要从LRU链表上获取到可重用的buffer。但是,LRU链表上的buffer并非都是立即可重用的,还会存在一些块正在被读写或者已经被别的用户所等待。根据LRU算法,查找可重用的buffer是从链表的LRU端开始查找的,如果这一段的前面存在这种不能理解被重用的buffer,则需要跳过去,查找链表中的下一个buffer。“free buffer inspected”就是被跳过去的buffer的数目。
如果Oracle用户进程达到查找块数限制后还没有找到空闲缓存,它就停止查找LRU链表,并且通过信号同志DBW0进程将脏缓存写入磁盘去。
2) 全表扫描
当发生全表扫描(Full Table Scan)时,用户进程读取表的数据块,并将他们放在LRU链表的LRU端(和上面不同,不是放在MRU端)。这样做的目的是为了使全表扫描的数据尽快被移出。因为全表扫描一般发生的频率较低,并且全表扫描的数据块大部分在以后都不会被经常使用到。
而如果你希望全表扫描的数据能被cache住,使之在扫描时放在MRU端,可以通过在创建或修改表(或簇)时,指定CACHE参数。
3) Flush Buffer
回顾一下前面一个用户进程访问一个数据块的过程,如果访问的数据块不在buffer cache中,就需要扫描LRU链表,当达到扫描块数限制后还没有找到空闲buffer,就需要通知DBW0将脏缓存回写到磁盘。如果一个系统中存在大量的脏缓冲,那么就可能导致用户进程访问数据性能下降。
我们可以通过人工干预将所有脏缓冲回写到磁盘去,这就是flush buffer。
在9i,可以用以下语句:
alter system set events = 'immediate trace name flush_cache'; --9i
在10g,可以用以下方式(9i的方式在10g仍然有效):
alter system flush buffer_cache; -- 10g
另外,9i的设置事件的方式可以是针对系统全部的,也可以是对会话的(即将该会话造成的脏缓冲回写)。
1.1.2 Buffer Cache的重要参数配置
1) Buffer Cache的大小配置
由于Buffer Cache中存放的是从数据文件中来的数据块的拷贝,因此,它的大小的计算也是以块的尺寸为基数的。而数据块的大小是由参数db_block_size指定的。9i以后,块的大小默认是8K,它的值一般设置为和操作系统的块尺寸相同或者它的倍数。
而参数db_block_buffers则指定了Buffer Cache中缓存块数。因此,buffer cache的大小就等于db_block_buffers * db_block_size。
在9i以后,Oracle引入了一个新参数:db_cache_size。这个参数可以直接指定Buffer Cache的大小,而不需要通过上面的方式计算出。它的默认值48M,这个数对于一个系统来说一般是不够用的。
10G中提供了自动内存管理,通过使用sga_target在在多个组件间自动分配内存以保证最有效的内存使用.如shared pool javapool largepool buffer cache都无需显式设置这些组件的大小,默认都是0,当某个组件需要内存时,可以通过内部自动调整机制请求内存转移.
注意:db_cache_size和db_block_buffers是不能同时设置的,否则实例启动时会报错。
SQL> alter system set db_block_buffers=16384 scope=spfile;
system altered.
SQL> alter system set db_cache_size=20M scope=memory;
system altered.
SQL> startup force
ORA-00381: cannot use both new and old parameters for buffer cache size specification
9i中,推荐使用db_cache_size来指定buffer cache的大小。
在OLTP系统中,对于DB_CACHE_SIZE的设置,推荐配置是:
DB_CACHE_SIZE = SGA_MAX_SIZE/2~ SGA_MAX_SIZE*2/3
最后,DB_CACHE_SIZE是可以联机修改的,即实例无需重启,除非增大Buffer Cache导致SGA实际大小大于SGA_MAX_SIZE。
2) 多种块尺寸系统中的Buffer Cache的配置
从9i开始,Oracle支持创建不同块尺寸的表空间,并且可以为不同块尺寸的数据块指定不同大小的buffer cache。
9i以后,除了SYSTEM表空间和TEMPORARY表空间必须使用标准块尺寸外,所有其他表空间都可以最多指定四种不同的块尺寸。而标准块尺寸还是由上面的所说的参数db_block_size来指定。而db_cache_size则是标致块尺寸的buffer cache的大小。
非标准块尺寸的块大小可以在创建表空间(CREATE TABLESPACE)是通过BLOCKSIZE参数指定。而不同块尺寸的buffer cache的大小就由相应参数DB_nK_CACHE_SZIE来指定,其中n可以是2,4,8,16或者32。例如,你创建了一个块大小为16K的非标准块尺寸的表空间,你就可以通过设置DB_16K_CACHE_SIZE为来指定缓存这个表空间数据块的buffer cache的大小。
任何一个尺寸的Buffer Cache都是不可以缓存其他尺寸的数据块的。因此,如果你打算使用多种块尺寸用于你的数据库的存储,你必须最少设置DB_CACHE_SIZE和DB_nK_CACHE_SIZE中的一个参数(10g后,指定了SGA_TARGET就可以不需要指定Buffer Cache的大小)。并且,你需要给你要用到的非标准块尺寸的数据块指定相应的Buffer Cache大小。这些参数使你可以为系统指定多达4种不同块尺寸的Buffer Cache。
另外,注意一点,DB_nK_CACHE_SIZE参数不能设定标准块尺寸的缓冲区大小。举例来说,如果 DB_BLOCK_SIZE设定为 4K,就不能再设定 DB_4K_CACHE_SIZE参数。
3)多缓冲池
可以配置不同的buffer cache,可以达到不同的cache数据的目的。比如,可以设置一部分buffer cache缓存过的数据在使用后后马上释放,使后来的数据可以立即使用缓冲池;还可以设置数据进入缓冲池后就被keep住不再释放。部分数据库对象(表、簇、索引以及分区)可以控制他们的数据缓存的行为,而这些不同的缓存行为就使用不同缓冲池。
保持缓冲池(Keep Buffer Pool)用于缓存那些永久驻入内存的数据块。它的大小由参数DB_KEEP_CACHE_SZIE控制;
回收缓冲池(Recycle Buffer Pool)会立即清除那些不在使用的数据缓存块。它的大小由参数DB_RECYLE_CACHE_SIZE指定;
默认的标准缓存池,也就是上面所说的DB_CACHE_SIZE指定。
这三个参数相互之间是独立的。并且他们都只适用于标准块尺寸的数据块。与8i兼容参数DB_BLOCK_BUFFERS相应的,DB_KEEP_CACHE_SIZE对应有BUFFER_POOL_KEEP、DB_RECYLE_CACHE_SIZE对应有BUFFER_POOL_RECYCLE。同样,这些参数之间是互斥的,即DB_KEEP_CACHE_SIZE和BUFFER_POOL_KEEP之间只能设置一个。
4) 缓冲池建议器
从9i开始,Oracle提供了一些自动优化工具,用于调整系统配置,提高系统性能。建议器就是其中一种。建议器的作用就是在系统运行过程中,通过监视相关统计数据,给相关配置在不同情况下的性能效果,提供给DBA做决策,以选取最佳的配置。
9i中,Buffer Cache就有了相应的建议器。参数db_cache_advice用于该建议器的开关,默认值为FALSE(即关)。当设置它为TRUE后,在系统运行一段时间后,就可以查询视图v$db_cache_advice来决定如何使之DB_CACHE_SIZE了。关于这个建议器和视图,我们会在下面的内容中介绍。
5) 其他相关参数
DB_BLOCK_LRU_LATCHES
LRU链表作为一个内存对象,对它的访问是需要进行锁(latch)控制的,以防止多个用户进程同时使用一个空闲缓存块。DB_BLOCK_LRU_LATCHES设置了LUR latch的数量范围。Oracle通过一系列的内部检测来决定是否使用这个参数值。如果这个参数没有设置,Oracle会自动为它计算出一个值。一般来说,oracle计算出来的值是比较合理,无需再去修改。
9i以后这个参数是隐含参数。对于隐含参数,我建议在没有得到Oracle支持的情况下不要做修改,否则,如果修改了,Oracle是可以拒绝为你做支持的。
DB_WRITER_PROCESSES
在前面分析Oracle读取Buffer Cache时,提到一个Oracle重要的后台进程DBW0,这个(或这些)进程负责将脏缓存块写回到数据文件种去,称为数据库书写器进程(Database Writer Process)。DB_WRITER_PROCESSES参数配置写进程的个数,各个进程以DBWn区分,其中n>=0,是进程序号。一般情况下,DB_WRITER_PROCESSES = MAX(1, TRUNC(CPU数/8))。也就是说,CPU数小于8时,DB_WRITER_PROCESSES为1,即只有一个写进程DBW0。这对于一般的系统来说也是足够用。当你的系统的修改数据的任务很重,并且已经影响到性能时,可以调整这个参数。这个参数不要超过CPU数,否则多出的进程也不会起作用,另外,它的最大值不能超过20。
DBWn进程除了上面提到的在用户进程读取buffer cache时会被触发,还能被Checkpoint触发(Checkpoint是实例从redo log中做恢复的起始点)。
1.2 Share Pool
SGA中的共享池由库缓存(Library Cache)、字典缓存(Dictionary Cache)、用于并行执行消息的缓冲以及控制结构组成。
Shared Pool的大小由参数SHARED_POOL_SIZE决定。9i中,在32位系统下,这个参数的默认值是8M,而64位系统下的默认值位64M。最大为4G。 10g 以后可以通过SGA_TARGET 参数来自动调整。
对于Shared Pool的内存管理,是通过修正过的LRU算法表来实现的。
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的用户都可以访问这两个地方以获取数据字典信息。
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;
Shared Pool能被分成几个区域,分别被不同的latch(latch数最大为7,可以通过隐含参数_kghdsidx_count设置)保护。
表x$kghlu可以查看shared pool中的LRU列表。当满足以下条件之一时,shared pool会分为多个区,分别有不同的LRU链表管理:
1)在10g之前版本,如果shared pool大于128M、CPU数量大于4;
2)Oracle数据库版本为10g
这时,在x$kghlu中就会对应不同记录。
1.2.4 保留共享池
前面提到,如果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字节的内存请求,是不会清出保留区的内存块的,相反亦然。
1.2.5 将重要、常用对象保持(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
这个参数前面也已经介绍,设置了进入保留区的对象大小的阀值。
1.3 重做日志缓存(Redo Log Buffer)
Redo Log Buffer是SGA中一段保存数据库修改信息的缓存。这些信息被存储在重做条目(Redo Entry)中.重做条目中包含了由于INSERT、UPDATE、DELETE、CREATE、ALTER或DROP所做的修改操作而需要对数据库重新组织或重做的必须信息。在必要时,重做条目还可以用于数据库恢复。
重做条目是Oracle数据库进程从用户内存中拷贝到Redo Log Buffer中去的。重做条目在内存中是连续相连的。后台进程LGWR负责将Redo Log Buffer中的信息写入到磁盘上活动的重做日志文件(Redo Log File)或文件组中去的。
参数LOG_BUFFER决定了Redo Log Buffer的大小。它的默认值是512K(一般这个大小都是足够的),最大可以到4G。10g中可通过参数自动设置。当系统中存在很多的大事务或者事务数量非常多时,可能会导致日志文件IO增加,降低性能。这时就可以考虑增加LOG_BUFFER。
但是,Redo Log Buffer的实际大小并不是LOB_BUFFER的设定大小。为了保护Redo Log Buffer,oracle为它增加了保护页(一般为11K):
SQL> select * from v$sgastat where name = 'log_buffer';
POOL NAME BYTES
------------ -------------------------- ----------
log_buffer 7135232
SQL> show parameter log_buffer
NAME TYPE VALUE
------------------------------------ ----------- ----------------
log_buffer integer 7024640
SQL>
1.4 大池(large pool)
大池是SGA中的一块可选内存池,根据需要时配置。在以下情况下需要配置大池:
1) 用于共享服务(Shared Server MTS方式中)的会话内存和Oracle分布式事务处理的Oracle XA接口
2) 使用并行查询(Parallel Query Option PQO)时
3) IO服务进程
4) Oracle备份和恢复操作(启用了RMAN时)
通过从大池中分配会话内存给共享服务、Oracle XA或并行查询,oracle可以使用共享池主要来缓存共享SQL,以防止由于共享SQL缓存收缩导致的性能消耗。此外,为Oracle备份和恢复操作、IO服务进程和并行查询分配的内存一般都是几百K,这么大的内存段从大池比从共享池更容易分配得到。
参数LARGE_POOL_SIZE设置大池的大小。大池是属于SGA的可变区(Variable Area)的,它不属于共享池。对于大池的访问,是受到large memory latch保护的。大池中只有两种内存段:空闲(free)和可空闲(freeable)内存段。它没有可重建(recreatable)内存段,因此也不用LRU链表来管理(这和其他内存区的管理不同)。大池最大大小为4G。
为了防止大池中产生碎片,隐含参数_LARGE_POOL_MIN_ALLOC设置了大池中内存段的最小大小,默认值是16K(同样,不建议修改隐含参数)。
此外,large pool是没有LRU链表的。
1. 5 Java池(Java Pool)
Java池也是SGA中的一块可选内存区,它也属于SGA中的可变区。
Java池的内存是用于存储所有会话中特定Java代码和JVM中数据。Java池的使用方式依赖与Oracle服务的运行模式。
Java池的大小由参数JAVA_POOL_SIZE设置。Java Pool最大可到1G。
在Oracle 10g以后,提供了一个新的建议器——Java池建议器——来辅助DBA调整Java池大小。建议器的统计数据可以通过视图V$JAVA_POOL_ADVICE来查询。如何借助建议器调整Java池的方法和使用Buffer Cache建议器类似,可以参考Buffer Cache中关于建议器部分。
1.6 流池(Streams Pool)
流池是Oracle 10g中新增加的。是为了增加对流的支持。
流池也是可选内存区,属于SGA中的可变区。它的大小可以通过参数STREAMS_POOL_SIZE来指定。如果没有被指定,oracle会在第一次使用流时自动创建。如果设置了SGA_TARGET参数,Oracle会从SGA中分配内存给流池;如果没有指定SGA_TARGET,则从buffer cache中转换一部分内存过来给流池。转换的大小是共享池大小的10%。
Oracle同样为流池提供了一个建议器——流池建议器。建议器的统计数据可以通过视图V$STREAMS_POOL_ADVICE查询。使用方法参看Buffer Cache中关于优化器部分。
二. PGA
PGA(Program Global Area程序全局区)是一块包含一个服务进程的数据和控制信息的内存区域。它是Oracle在一个服务进程启动是创建的,是非共享的。一个Oracle进程拥有一个PGA内存区。一个PGA也只能被拥有它的那个服务进程所访问,只有这个进程中的Oracle代码才能读写它。因此,PGA中的结构是不需要Latch保护的。
我们可以设置所有服务进程的PGA内存总数受到实例分配的总体PGA(Aggregated PGA)限制。
在专有服务器(Dedicated Server)模式下,Oracle会为每个会话启动一个Oracle进程;而在多线程服务(Multi-Thread Server MTS)模式下,由多个会话共享通一个Oracle服务进程。
PGA中包含了关于进程使用到的操作系统资源的信息,以及一些关于进程状态的信息。而关于进程使用的Oracle共享资源的信息则是在SGA中。这样做可以使在进程以外中止时,能够及时释放和清除这些资源。
•Stack Space是用来存储用户会话变量和数组的存储区域;
•User Session Data是为用户会话使用的附加存储区。
|--Session Information
|--Sort Area
|--Cursor Information
注意Session information(用户会话信息)在独占服务器中与在共享服务器中所处的内存区域是不同的。
2.1 PGA的组成
PGA由两组区域组成:固定PGA和可变PGA(或者叫PGA堆,PGA Heap【堆——Heap就是一个受管理的内存区】)。固定PGA和固定SGA类似,它的大小时固定的,包含了大量原子变量、小的数据结构和指向可变PGA的指针。
可变PGA是一个内存堆。它的内存段可以通过视图X$KSMPP(另外一个视图X$KSMSP可以查到可变SGA的内存段信息,他们的结构相同)查到。PGA堆包含用于存放X$表的的内存(依赖与参数设置,包括DB_FILES、CONTROL_FILES)。
总的来说,PGA的可变区中主要分为以下三部分内容:
1)私有SQL区;
2)游标和SQL区
3)会话内存
2.1.1 私有SQL区(Private SQL Area)
私有SQL区包含了绑定变量值和运行时期内存结构信息等数据。每一个运行SQL语句的会话都有一个块私有SQL区。所有提交了相同SQL语句的用户都有各自的私有SQL区,并且他们共享一个共享SQL区。因此,一个共享SQL区可能和多个私有共享区相关联。
一个游标的私有SQL区又分为两个生命周期不同的区:
永久区:包含绑定变量信息。当游标关闭时被释放。
运行区:当执行结束时释放。
创建运行区是一次执行请求的第一步。对于INSERT、UPDATE和DELETE语句,Oracle在语句运行结束时释放运行区。对于查询操作,Oracle只有在所有记录被fetch到或者查询被取消时释放运行区。
2.1.2 游标和SQL区(Cursors and SQL Areas)
一个Oracle预编译程序或OCI程序的应用开发人员能够很明确的打开一个游标,或者控制一块特定的私有SQL区,将他们作为程序运行的命名资源。另外,oracle隐含的为一些SQL语句产生的递归调用(前面有介绍,读取数据字典信息)也使用共享SQL区。
私有SQL区是由用户进程管理的。如何分配和释放私有SQL区极大的依赖与你所使用的应用工具。而用户进程可以分配的私有SQL区的数量是由参数OPEN_CURSORS控制的,它的默认值是50。
在游标关闭前或者语句句柄被释放前,私有SQL区将一直存在(但其中的运行区是在语句执行结束时被释放,只有永久区一直存在)下去。应用开发人员可以通过将所有打开的不再使用的游标都关闭来释放永久区,以减少用户程序所占用的内存。
2.1.3 会话内存(Session Memory)
会话内存是一段用于保存会话变量(如登录信息)和其他预会话相关信息的内存。对于共享服务器模式下,会话内存是共享的,而不是私有的。
对于复杂的查询(如决策支持系统中的查询),运行区的很大一部分被那些内存需求很大的操作分配给SQL工作区(SQL Work Area)。这些操作包括:
基于排序的操作(ORDER BY、GROUP BY、ROLLUP、窗口函数);
Hash Join
Bitmap merge
Bitmap create
例如,一个排序操作使用工作区(这时也可叫排序区Sort Area)来将一部分数据行在内存排序;而一个Hash Join操作则使用工作区(这时也可以叫做Hash区 Hash Area)来建立Hash表。如果这两种操作所处理的数据量比工作区大,那就会将输入的数据分成一些更小的数据片,使一些数据片能够在内存中处理,而其他的就在临时表空间的磁盘上稍后处理。尽管工作区太小时,Bitmap操作不会将数据放到磁盘上处理,但是他们的复杂性是和工作区大小成反比的。因此,总的来说,工作区越大,这些操作就运行越快。
工作区的大小是可以调整的。一般来说,大的工作区能让一些特定的操作性能更佳,但也会消耗更多的内存。工作区的大小足够适应输入的数据和相关的SQL操作所需的辅助的内存就是最优的。如果不满足,因为需要将一部分数据放到临时表空间磁盘上处理,操作的响应时间会增长。
2.2 PGA内存自动管理
SQL工作区可以是自动的、全局的管理。DBA只要设置参数PGA_AGGREGATE_TARGET给一个实例的PGA内存指定总的大小。设置这个参数后,Oracle将它作为一个总的全局限制值,尽量使所有Oracle服务进程的PGA内存总数不超过这个值。
在这个参数出现之前,DBA要调整参数SORT_AREA_SIZE、 HASH_AREA_SIZE,、BITMAP_MERGE_AREA_SIZE和CREATE_BITMAP_AREA_SIZE(关于这些参数,我们会在后面介绍),使性能和PGA内存消耗最佳。对这些参数的调整是非常麻烦的,因为即要考虑所有相关的操作,使工作区适合它们输入数据大小,又要使PGA内存不消耗过大导致系统整体性能下降。
9i以后,通过设置了参数PGA_AGGREGATE_TARGET,使所有会话的工作区的大小都是自动分配。同时,所有*_AREA_SIZE参数都会失效。在任何时候,实例中可用于工作区的PGA内存总数都是基于参数PGA_AGGREGATE_TARGET的。工作区内存总数等于参数PGA_AGGREGATE_TARGET的值减去系统其他组件(如分配给会话的PGA内存)的内存消耗。分配给Oracle进程的PGA内存大小是根据它们对内存的需求情况来的。
参数WORKAREA_SIZE_POLICY决定是否使用PGA_AGGREGATE_TARGET来管理PGA内存。它有两个值:AUTO和MANUAL。默认是AUTO,即使用PGA_AGGREGATE_TARGET来管理PGA内存。其实,从参数WORKAREA_SIZE_POLICY的名字上可以看出,Oracle的PGA内存自动管理只会调整工作区部分,而非工作区部分(固定PGA区)则不会受影响。
还有注意一点就是:10g之前,PGA_AGGREGATE_TARGET只在专用服务模式下生效。而10g以后,PGA内存自动管理在专有服务模式(Dedicated Server)和MTS下都有效。另外,9i在OpenVMS系统上还不支持PGA内存自动管理,但10g支持。
设置了PGA_AGGREGATE_TARGET以后,每个进程PGA内存的大小也是受限制的:
串行操作时,每个进程可用的PGA内存为MIN(PGA_AGGREGATE_TARGET * 5%, _pga_max_size/2),其中隐含参数_pga_max_size的默认值是200M,同样不建议修改它。
并行操作时,并行语句可用的PGA内存为PGA_AGGREGATE_TARGET * 30% / DOP(Degree Of Parallelism并行度)。
2.3 专有服务(Dedicated Server)和共享服务(Shared Server)
对PGA内存的管理和分配,很大程度上依赖与服务模式。下面这张表显示了在不同模式下,PGA内存不同部分的分配的异同:
内存区 | 专有服务 | 共享服务 |
会话内存 | 私有的 | 共享的 |
永久区所在区域 | PGA | SGA |
SELECT语句的运行区所在区域 | PGA | PGA |
DML/DDL语句的运行区所在区域 | PGA | PGA |
三. UGA (The User Global Area)
PGA是一段包含一个Oracle服务或后台进程的数据和控制信息的内存。PGA的大小依赖与系统的配置。在专用服务(Dedicated Server)模式下,一个服务进程与一个用户进程相关,PGA就包括了堆空间和UGA。而UGA(User Global Area用户全局区)由用户会话数据、游标状态和索引区组成。在共享服务(MTS)模式下,一个共享服务进程被多个用户进程共享,此时UGA是Shared Pool或Large Pool的一部分(依赖与配置)。
许多DBA都不理解PGA和UGA之间的区别。其实这种区别可以简单的理解为进程和会话直接的区别。在专用服务模式下,进程和会话是一对一的;而在MTS模式下,进程和会话是一对多的关系。PGA是服务于进程的,它包含的是进程的信息;而UGA是服务于会话的,它包含的是会话的信息。因此,MTS模式下,PGA和UGA之间的关系也是一对多的。
UGA中包含了一个会话的信息,包括:
1)打开游标的永久区和运行区;
2)包的状态信息,特别是包的变量;
3)Java会话的信息;
4)激活的角色;
5)激活的跟踪事件(ALTER SESSION SET EVENT …);
6)起作用的NLS参数(SELECT * FROM NLS_SESSION_PARAMETERS;);
7)所有打开的db link;
8)会话对于信任的Oracle的托管访问标记(mandatory access control (MAC)
和PGA一样,UGA也由两组区组成,固定UGA和可变UGA(或者说UGA堆)。固定UGA包含了大概70个原子变量、小的数据结构以及指向UGA堆的指针。
UGA heap中的段可以通过表X$KSMUP查到(它的结构和X$KSMSP相同)。UGA堆包含了存储一些固定表(X$表)的永久内存(依赖与特定参数的设置,如OPEN_CURSORS,OPEN_LINKS和MAX_ENABLED_ROLES)。除此以外,大部分的UGA用于私有SQL区。UGA内存的所在依赖于会话的设置。在专用服务模式下,会话和进程是一对一的关系,UGA位于PGA中。固定UGA是PGA中的一段内存段,而UGA堆是PGA的子堆。在MTS模式下,固定UGA是shared pool中的一段内存段,而UGA堆是Large Pool的子堆,如果从large pool分配失败,则从shared pool中分配。
MTS模式下,可以通过Profile中的PRIVATE_SGA项(通过dba_profiles查看)来控制每个UGA占用的SGA的总的大小,但是不建议这样做。
Oracle 9.2以后,有一个新的隐含参数:_use_realfree_heap。当设置这个参数为true时,Oracle会为CGA、UGA单独分配堆,而不从PGA中分配。它的默认值为false,而当设置了pga_aggregate_target后,它的值自动被改为true。
四. CGA (The Call Global Area)
与其他的全局区不同,CGA(Call Global Area调用全局区)的存在是瞬间的。它只存在于一个调用过程中。对于实例的一些低层次的调用需要CGA,包括:
1)解析一条SQL语句;
2)执行一条SQL语句;
3)取一条SELECT语句的输出值。
如果语句产生了递归调用,则需要为每个递归调用分配一个CGA。如上所述,递归调用是在语句解析、优化器产生语句查询计划、DML操作时需要查询或修改数据字典信息的调用。
无论UGA存在于PGA还是SGA,CGA都是PGA的subheap。因为无论那种模式,会话在做调用时总需要一个进行进行处理。这一点很重要,特别是在MTS模式下时,如果发现一次调用很久没有响应,则可能需要增加PGA的大小。
当然,调用并不是只通过CGA中的数据结构来工作。实际上,调用所需要的大部分的重要数据结构都来自于UGA。例如私有SQL取和排序区都存放在UGA中,因为调用结束后,它们是被保留的。CGA中只包含了那些调用结束后可以被释放的数据。例如,CGA中包含了直接IO缓存、关于递归调用的信息、用于表达式评估(产生查询计划时)的的堆空间和其他一些临时数据。
Java调用内存也分配在CGA中。它被分为三部分空间:堆空间、新空间和老空间。在调用期间(调用长短依赖于使用期长短和大小),在新空间和老空间中的内存段不再使用的内存段将被垃圾收集器回收。
五.软件代码区(Software Code Area)
软件代码区是一部分用于存放那些正在运行和可以被运行的代码(Oracle自身的代码)的内存区。Oracle代码一般存储在一个不同于用户程序存储区的软件代码区,而用户程序存储区是排他的、受保护的区域。
软件区的大小一般是固定的,只有Oracle软件升级或重装后才会改变。在不同操作系统下,这部分区域所要求的大小也不同。
软件区是只读的,可以被安装成共享的或非共享的。可能的情况下,Oracle代码是共享的,这样所有Oracle用户都可以直接访问这些代码,而不需要各自保存一份拷贝在自己的内存中。这样可以节省大量内存并提高整体性能。
而用户程序也可以是共享的或非共享的。一些Oracle工具(如SQL Plus)能被安装成共享的,但有些不能。如果一台机器运行多个实例,这些实例可以使用同一个Oracle代码区。
另外要注意的是:并不是所有操作系统都能将软件区安装成共享的,如Windows。
更多详细内容请参考: Oracle 内存全面分析
下载地址:http://download.csdn.net/source/1988869
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/196700/viewspace-773801/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/196700/viewspace-773801/