Oracle 内存 架构

原创   Oracle 内存 架构 详解

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_siz e指定的。 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= 20 M 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

 

 

 

 

注:整理自网络资料

 ------------------------------------------------------------------------------
Blog: http://blog.csdn.net/tianlesoftware
网上资源: http://tianlesoftware.download.csdn.net
相关视频:http://blog.csdn.net/tianlesoftware/archive/2009/11/27/4886500.aspx
DBA1 群:62697716(满); DBA2 群:62697977(满)
DBA3 群:63306533;     聊天 群:40132017

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值