Oracle内存全面分析(1)-1Oracle 的内存架构组成_1SGA.1SGA简介以及调整参数

Oracle内存全面分析(1)



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

 

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

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

 

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

 

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

 

1.   Oracle的内存架构组成

 

Oracle的内存,从总体上讲,可以分为两大块:共享部分(主要是SGA)和进程独享部分(主要是PGA和UGA)。共享连接模式时,UGA位于SGA上;专用连接模式时,UGA位于PGA上。

而这两部分内存里面,根据功能不同,还分为不同内存池(Pool)和内存区(Area)。


下面就是Oracle内存构成框架图:

 

 

SGA

 

Share Pool

 

Buffer Cache

 

Redo Log Buffer

 

 

Java Pool

 

Stream Pool(10g)

 

Large Pool

 

 

PGA(这部分应该是叫SQL工作区吧)*n

Bitmap merge area

Sort Area

Hash Area

 

 

UGA*n

CUA*n

 

 

 注释:上图中pga的组成部分有问题应该。

shared pool组成(图中的other指的应该是control structures,如锁、资源等):



PGA和UGA的组成:

图中的stack space指的应该是fixed pga部分?

cursor state for storing runtime information on cursors,故cursor state就是private sql area中的持续区部分,

而SQL work area就是private sql area中的运行区部分


上述两图来自oracle 11g教材D50102GC20_sg1


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

1.1.            SGA(System Global Area)

 

SGA(System Global Area 系统全局区域)是一组包含一个Oracle实例的数据和控制信息的共享内存结构。这句话可以说是SGA的定义。

虽然简单,但其中阐述了SGA几个很重要的特性:

1、SGA的构成——数据和控制信息,我们下面会详细介绍;

2、SGA是共享的,即当有多个用户同时登录了这个实例,SGA中的信息可以被它们同时访问(当涉及到互斥的问题时,由latch和enquence(排队  Vt.)控制);

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中了,而且不会改变,所以这部分又称为固定SGA(Fixed SGA)。这部分区域的大小一般小于100K。

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

Shared Pool、Java Pool、Large Pool和Streams Pool这几块内存区的大小是相应系统参数设置而改变的,所以有通称为可变SGA(Variable SGA)


注释:

像Shared Pool是一个堆,所以即使实例启动时其对应的系统参数初始化了它的大小,之后Shared Pool的大小也可能会改变的,那其他几个pool是否也这样,即系统参数的设定后其大小还会变(即使参数值未变),还是其大小完全依赖于(或叫决定于)系统参数的设定??????


1.1.1.   SGA的重要参数和特性

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

·        SGA_MAX_SIZE

SGA区包括了各种缓冲区和内存池,而大部分都可以通过特定的参数来指定他们的大小。但是,作为一个昂贵的资源,一个系统的物理内存大小是有限。尽管对于CPU的内存寻址来说,是无须关心实际的物理内存大小的(关于这一点,后面会做详细的介绍,即操作系统使用虚拟内存机制来屏蔽物理内存大小的差异),但是过多的使用虚拟内存导致page in/out,会大大影响系统的性能,甚至可能会导致系统crash。所以需要有一个参数来控制SGA使用虚拟内存的最大大小,这个参数就是SGA_MAX_SIZE。

当实例启动后,(在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区的大小要小于物理内存的大小),否则,会导致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_SIZE(10g中的新内存池) + LOG_BUFFERS+11K(Redo Log Buffer的保护页) + 1MB + 16M(SGA内部内存消耗,适合于9i及之前版本)

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

注释:

11K(Redo Log Buffer的保护页)

如果OS支持内存保护,log buffer将会被两个保护页面包围起来以免被一些ORACLE的错误进程损坏log buffer.

http://blog.csdn.net/haiross/article/details/41211225


·        PRE_PAGE_SGA

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

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

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

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占用的物理内存只有168M,远小于SGA的最大值288M(实际上,这部分物理内存中还有一部分进程的PGA和Oracle Service占用的内存),而虚拟内存(这里的虚拟内存指的是,虚拟内存机制用到的位于磁盘上的页文件(pagefile))则为340M。


这时看到,实例启动后物理内存达到了最大343M,于虚拟内存(这里的虚拟内存指的是,虚拟内存机制用到的位于磁盘上的页文件(pagefile))相当。这时,oracle实例已经将所有SGA分配到物理内存。

注释:

虚拟内存  这个词有两层含义:

一指的是虚拟内存机制,二指的是虚拟内存机制用到的位于磁盘上的页文件(pagefile)。


当参数设置为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中引入的一个非常重要的参数。


而引入SGA_TARGET参数的背景原因(即存在如下说的矛盾)为:

1、在10g之前,SGA的各个内存区的大小都需要通过各自的参数指定,并且都无法超过参数指定大小的值,尽管他们之和可能并没有达到SGA的最大限制。

2、此外,一旦分配后,各个区的内存只能给本区使用,相互之间是不能共享的:

拿SGA中两个最重要的内存区Buffer Cache和Shared Pool来说,它们两个对实例的性能影响最大,但是就有这样的矛盾存在:在内存资源有限的情况下,某些时候数据被cache的需求非常大,为了提高buffer hit,就需要增加Buffer Cache,但由于SGA有限,只能从其他区“抢”过来——如缩小Shared Pool,增加Buffer Cache;而有时又有大块的PLSQL代码被解析驻入内存中,导致Shared Pool不足,甚至出现4031错误,又需要扩大Shared Pool,这时可能又需要人为干预(即人为手动调整相应内存区大小,使一个空闲的内存区调小,再调整另一个空间不足的内存区变大),从Buffer Cache中将内存夺回来。


Oracle10g中引入一)有了这个新的特性后,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设置为TRUE后,意味着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这些参数作用失效。



Sga_target设置为TRUE后SGA_MAX_SIZE参数的作用依旧不会失效。

对于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位平台中,这个参数被忽略。

1.1.2.   关于SGA的重要视图

要了解和观察SGA的使用情况,并且根据统计数据来处理问题调整性能,主要有以下的几个系统视图。

·        v$sga

这个视图包括了SGA的的总体情况,只包含两个字段:name(SGA内存区名字)和value(内存区的值,单位为字节)。它的结果和show sga的结果一致,显示了SGA各个区的大小:

SQL> select * from v$sga;
 
NAME                      VALUE
-------------------- ----------
Fixed Size              1248428
Variable Size         117441364
Database Buffers      138412032
Redo Buffers            7139328
 
4 rows selected.
 
SQL> show sga
 
Total System Global Area  264241152 bytes
Fixed Size                  1248428 bytes
Variable Size             117441364 bytes
Database Buffers          138412032 bytes
Redo Buffers                7139328 bytes
SQL>
·        v$sgastat

这个视图比较重要。它记录了关于sga的统计信息。包含三个字段:Name(SGA内存区的名字);Bytes(内存区的大小,单位为字节);Pool(这段内存所属的内存池)。

这个视图尤其重要的是,它详细记录了个各个池(Pool)内存分配情况,对于定位4031错误有重要参考价值。

以下语句可以查询Shared Pool空闲率:

SQL> select to_number(v$parameter.value) value, v$sgastat.BYTES,
  2         (v$sgastat.bytes/v$parameter.value)*100 "percent free"
  3      from v$sgastat, v$parameter
  4      where v$sgastat.name= 'free memory'
  5      and v$parameter.name = 'shared_pool_size'
  6      and v$sgastat.pool='shared pool'
  7  ;
 
     VALUE      BYTES percent free
---------- ---------- ------------
 503316480  141096368 28.033329645
 
SQL>
·        v$sga_dynamic_components

这个视图记录了SGA各个动态内存区(即SGA中的Variable area部分里的各个内存区,如shared pool)的情况,它的统计信息是基于已经完成了的,针对SGA动态内存区大小调整的操作,字段组成如下:

字段

数据类型

描述

COMPONENT

VARCHAR2(64)

内存区名称

CURRENT_SIZE

NUMBER

当前大小

MIN_SIZE

NUMBER

自从实例启动后的最小值

MAX_SIZE

NUMBER

自从实例启动后的最大值

OPER_COUNT

NUMBER

自从实例启动后的调整次数

LAST_OPER_TYPE

VARCHAR2(6)

最后一次完成的调整动作,值包括:

  • GROW (增加)
  • SHRINK (缩小)

LAST_OPER_MODE

VARCHAR2(6)

最后一次完成的调整动作的模式,包括:

  • MANUAL (手动)
  • AUTO (自动)

LAST_OPER_TIME

DATE

最后一次完成的调整动作的开始时间

GRANULE_SIZE

NUMBER

GRANULE大小(关于granule后面详细介绍)

·        V$SGA_DYNAMIC_FREE_MEMORY

这个视图只有一个字段,一条记录:当前SGA可用于动态调整SGA内存区的空闲区域大小。

它的值相当于(SGA_MAX_SIZE – SGA各个区域设置大小的总和)。

当设置了SGA_TARGET后,它的值一定为0(为什么就不需要我再讲了吧^_^,因为当指定SGA_TARGET小于SGA_MAX_SIZE,实例重启后,SGA_MAX_SIZE就自动变为和SGA_TARGET一样的值了。)。

下面的例子可以很清楚的看到这个视图的作用:

SQL> select * from v$sga_dynamic_free_memory;
 
CURRENT_SIZE
--------------
0
 
SQL> show parameter shared_pool
 
NAME                                TYPE        VALUE
----------------------------------- ----------- ----------
shared_pool_size                    big integer 50331648
 
SQL> alter system set shared_pool_size=38M;
 
system altered.
 
SQL> show parameter shared_pool
 
NAME                                TYPE        VALUE
----------------------------------- ----------- ----------
shared_pool_size                    big integer 41943040
 
SQL> select * from v$sga_dynamic_free_memory;
 
CURRENT_SIZE
--------------
8388608

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值