Oracle内存全面分析(1)

Oracle内存全面分析(1)

[English ]

作者: fuyuncat

来源: www.HelloDBA.com

Oracle 的内存配置与oracle 性能息息相关。而且关于内存的错误(如40304031 错误)都是十分令人头疼的问题。可以说,关于内存的配置,是最影响Oracle 性能的配置。内存还直接影响到其他两个重要资源的消耗:CPUIO

 

首先,看看Oracle 内存存储的主要内容是什么:

  • 程序代码(PLSQLJava );
  • 关于已经连接的会话的信息,包括当前所有活动和非活动会话;
  • 程序运行时必须的相关信息,例如查询计划;
  • Oracle 进程之间共享的信息和相互交流的信息,例如锁;
  • 那些被永久存储在外围存储介质上,被cache 在内存中的数据(如redo log 条目,数据块)。

 

此外,需要记住的一点是,Oracle 的内存是与实例对应的。也就是说,一个实例就有一个独立的内存结构。

 

先从Oracle 内存的组成架构介绍。

 

1.   Oracle 的内存架构组成

 

Oracle 的内存,从总体上讲,可以分为两大块:共享部分(主要是SGA )和进程独享部分(主要是PGAUGA )。而这两部分内存里面,根据功能不同,还分为不同内存池(Pool )和内存区(Area )。下面就是Oracle 内存构成框架图:

 

 

SGA

 

Share Pool

 

Buffer Cache

 

Redo Log Buffer

 

 

Java Pool

 

Stream Pool(10g)

 

Large Pool

 

 

PGA*n

Bitmap merge area

Sort Area

Hash Area

 

 

UGA*n

CUA*n

 

 

 

下面分别介绍这两块内存区。

1.1.            SGA System Global Area

 

SGA System Global Area 系统全局区域)是一组包含一个Oracle 实例的数据和控制信息的共享内存结构。这句话可以说是SGA 的定义。虽然简单,但其中阐述了SGA 几个很重要的特性:1SGA 的构成——数据和控制信息,我们下面会详细介绍;2SGA 是共享的,即当有多个用户同时登录了这个实例,SGA 中的信息可以被它们同时访问(当涉及到互斥的问题时,由latchenquence 控制);3 、一个SGA 只服务于一个实例,也就是说,当一台机器上有多个实例运行时,每个实例都有一个自己的SGA ,尽管SGA 来自于OS 的共享内存区,但实例之间不能相互访问对方的SGA 区。

Oracle 进程和一个SGA 就构成了一个Oracle 实例。当实例启动时,Oracle 会自动从系统中分配内存给SGA ,而实例关闭时,操作系统会回收这些内存。下面就是当实例启动后,显示已经分配了SGA

 

SQL> startup

ORACLE instance started.

 

Total System Global Area  289406976 bytes

Fixed Size                  1248576 bytes

Variable Size             117441216 bytes

Database Buffers          163577856 bytes

Redo Buffers                7139328 bytes

Database mounted.

Database opened.

 

SQL>

 

SGA 区是可读写的。所有登录到实例的用户都能读取SGA 中的信息,而在oracle 做执行操作时,服务进程会将修改的信息写入SGA 区。

SGA 主要包括了以下的数据结构:

  • 数据缓冲(Buffer Cache
  • 重做日志缓冲(Redo Log Buffer
  • 共享池(Shared Pool
  • Java 池(Java Pool
  • 大池(Large Pool
  • 流池(Streams Pool --- 10g 以后才有)
  • 数据字典缓存(Data Dictionary Cache
  • 其他信息(如数据库和实例的状态信息)

最后的两种内存信息会被实例的后台进程所访问,它们在实例启动后就固定在SGA 中了,而且不会改变,所以这部分又称为固定SGAFixed SGA )。这部分区域的大小一般小于100K

此外,用于并非进程控制的锁(latch )的信息也包含在SGA 区中。

Shared Pool Java PoolLarge PoolStreams Pool 这几块内存区的大小是相应系统参数设置而改变的,所以有通称为可变SGAVariable SGA )。

1.1.1.   SGA 的重要参数和特性

在设置SGA 时,有一些很重要的参数,它们设置正确与否,会直接影响到系统的整体性能。下面一一介绍他们:

·        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 (一般有经验的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_SIZE10g 中的新内存池) + LOG_BUFFERS+11K(Redo Log Buffer 的保护页) + 1MB + 16M(SGA 内部内存消耗,适合于9i 及之前版本)

公式种涉及到的参数在下面的内容种会一一介绍。

·        PRE_PAGE_SGA

我们前面提到,oracle 实例启动时,会只载入各个内存区最小的大小。而其他SGA 内存只作为虚拟内存分配,只有当进程touch 到相应的页时,才会置换到物理内存中。但我们也许希望实例一启动后,所有SGA 都分配到物理内存。这时就可以通过设置PRE_PAGE_SGA 参数来达到目的了。

这个参数的默认值为FALSE ,即不将全部SGA 置入物理内存中。当设置为TRUE 时,实例启动会将全部SGA 置入物理内存中。它可以使实例启动达到它的最大性能状态,但是,启动时间也会更长(因为为了使所有SGA 都置入物理内存中,oracle 进程需要touch 所有的SGA 页)。

我们可以通过TopShow 工具(本站原创工具,可在http://www.HelloDBA.com/Download/TopShow.html 中下载)来观察windowsUnix 下的内存监控比较复杂,这里暂不举例)下参数修改前后的对比。

PRE_PAGE_SGA FALSE

SQL> show parameter sga

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- --------------------------

lock_sga                             boolean     FALSE

pre_page_sga                         boolean     FALSE

sga_max_size                         big integer 276M

sga_target                           big integer 276M

SQL> startup force

ORACLE instance started.

 

Total System Global Area  289406976 bytes

Fixed Size                  1248576 bytes

Variable Size             117441216 bytes

Database Buffers          163577856 bytes

Redo Buffers                7139328 bytes

Database mounted.

Database opened.

SQL>

启动后,Oracle 的内存情况

Oracle内存全面分析(1)_第1张图片

可以看到,实例启动后,oracle 占用的物理内存只有168M ,远小于SGA 的最大值288M (实际上,这部分物理内存中还有一部分进程的PGAOracle Service 占用的内存),而虚拟内存则为340M

Oracle内存全面分析(1)_第2张图片

这时看到,实例启动后物理内存达到了最大343M ,于虚拟内存相当。这时,oracle 实例已经将所有SGA 分配到物理内存。

当参数设置为TRUE 时,不仅在实例启动时,需要touch 所有的SGA 页,并且由于每个oracle 进程都会访问SGA 区,所以每当一个新进程启动时(在Dedicated Server 方式中,每个会话都会启动一个Oracle 进程),都会touch 一遍该进程需要访问的所有页。因此,每个进程的启动时间页增长了。所以,这个参数的设置需要根据系统的应用情况来设定。

在这种情况下,进程启动时间的长短就由系统内存的页的大小来决定了。例如,SGA 大小为100M ,当页的大小为4K 时,进程启动时需要访问100000/4=25000 个页,而如果页大小为4M 时,进程只需要访问100/4=25 个页。页的大小是由操作系统指定的,并且是无法修改的。

但是,要记住一点:PRE_PAGA_SGA 只是在启动时将物理内存分配给SGA ,但并不能保证系统在以后的运行过程不会将SGA 中的某些页置换到虚拟内存中,也就是说,尽管设置了这个参数,还是可能出现Page In/Out 。如果需要保障SGA 不被换出,就需要由另外一个参数LOCK_SGA 来控制了。

·        LOCK_SGA

上面提到,为了保证SGA 都被锁定在物理内存中,而不必页入/ 页出,可以通过参数LOCK_SGA 来控制。这个参数默认值为FALSE ,当指定为TRUE 时,可以将全部SGA 都锁定在物理内存中。当然,有些系统不支持内存锁定,这个参数也就无效了。

·        SGA_TARGET

这里要介绍的时Oracle10g 中引入的一个非常重要的参数。在10g 之前,SGA 的各个内存区的大小都需要通过各自的参数指定,并且都无法超过参数指定大小的值,尽管他们之和可能并没有达到SGA 的最大限制。此外,一旦分配后,各个区的内存只能给本区使用,相互之间是不能共享的。拿SGA 中两个最重要的内存区Buffer CacheShared Pool 来说,它们两个对实例的性能影响最大,但是就有这样的矛盾存在:在内存资源有限的情况下,某些时候数据被cache 的需求非常大,为了提高buffer hit ,就需要增加Buffer Cache ,但由于SGA 有限,只能从其他区“抢”过来——如缩小Shared Pool ,增加Buffer Cache ;而有时又有大块的PLSQL 代码被解析驻入内存中,导致Shared Pool 不足,甚至出现4031 错误,又需要扩大Shared Pool ,这时可能又需要人为干预,从Buffer Cache 中将内存夺回来。

有了这个新的特性后,SGA 中的这种内存矛盾就迎刃而解了。这一特性被称为自动共享内存管理(Automatic Shared Memory Management ASMM )。而控制这一特性的,也就仅仅是这一个参数SGA_TARGE 。设置这个参数后,你就不需要为每个内存区来指定大小了。SGA_TARGET 指定了SGA 可以使用的最大内存大小,而SGA 中各个内存的大小由Oracle 自行控制,不需要人为指定。Oracle 可以随时调节各个区域的大小,使之达到系统性能最佳状态的个最合理大小,并且控制他们之和在SGA_TARGET 指定的值之内。一旦给SGA_TARGET 指定值后(默认为0 ,即没有启动ASMM ),就自动启动了ASMM 特性。

设置了SGA_TARGET 后,以下的SGA 内存区就可以由ASMM 来自动调整:

  • 共享池(Shared Pool
  • Java 池(Java Pool
  • 大池(Large Pool
  • 数据缓存区(Buffer Cache
  • 流池(Streams Pool

对于SGA_TARGET 的限制,它的大小是不能超过SGA_MAX_SIZE 的大小的。

SQL> show parameter sga

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

lock_sga                             boolean     FALSE

pre_page_sga                         boolean     FALSE

sga_max_size                         big integer 276M

sga_target                           big integer 276M

SQL>

SQL>

SQL>

SQL> alter system set sga_target=280M;

alter system set sga_target=280M

*

ERROR at line 1:

ORA-02097: parameter cannot be modified because specified value is invalid

ORA-00823: Specified value of sga_target greater than sga_max_size

另外,当指定SGA_TARGET 小于SGA_MAX_SIZE ,实例重启后,SGA_MAX_SIZE 就自动变为和SGA_TARGET 一样的值了。

SQL> show parameter sga

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

lock_sga                             boolean     FALSE

pre_page_sga                         boolean     FALSE

sga_max_size                         big integer 276M

sga_target                           big integer 276M

 

SQL> alter system set sga_target=252M;

 

System altered.

 

SQL> show parameter sga

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

lock_sga                             boolean     FALSE

pre_page_sga                         boolean     FALSE

sga_max_size                         big integer 276M

sga_target                           big integer 252M

 

SQL> startup force

ORACLE instance started.

 

Total System Global Area  264241152 bytes

Fixed Size                  1248428 bytes

Variable Size             117441364 bytes

Database Buffers          138412032 bytes

Redo Buffers                7139328 bytes

Database mounted.

Database opened.

SQL> show parameter sga

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

lock_sga                             boolean     FALSE

pre_page_sga                         boolean     FALSE

sga_max_size                         big integer 252M

sga_target                           big integer 252M

SQL>

对于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 错误的几率。

·        use_indirect_data_buffers

这个参数使32 位平台使用扩展缓冲缓存基址,以支持支持4GB 多物理内存。设置此参数,可以使SGA 突破在32 位系统中的2G 最大限制。64 位平台中,这个参数被忽略。

 

Top

Copyright @2005 HelloDBA.Com All reseverd.

申明
by fuyuncat

你可能感兴趣的:(Oracle内存全面分析(1))