allaboutOraclememory-Oracle的内存管理(一)

2014-11-24 16:56:09 · 作者: · 浏览: 6

2.Oracle的内存管理

在这部分章节中,我们将从更底层的角度来了解Oracle的内存管理。当然,涉及到内存管理,就不可避免的要了解OS对内存的管理,在这一章节中,将谈到不少关于OS内存的管理知识。如果概念记得不清除了,可以找一本《操作系统》的书看看先。

2.1.Oracle内存管理基础

要了解内存管理,首先需要知道虚拟内存。而要了解虚拟内存,就先要知道CPU寻址。我们知道,目前主流的CPU都是32位或者64位的。那么这个位数指的是什么呢?就是指CPU的最大寻址能力。在CPU中,所有一切都是二进制表示的,那么一个32位CPU的寻址范围就是2^32=4G。但有可能一台机器的实际物理内存没有这么大,比如说只有2G。而程序员在编程的时候根本不用考虑实际物理内存多大,还是按照4G的内存来分配。这时,OS就提出了一个虚拟内存的概念,如果所寻址的数据实际上不在物理内存中,那就从“虚拟内存”中来获取。这个虚拟内存可以是一个专门文件格式的磁盘分区(比如UNIX下的swap分区),也可以是硬盘上的某个足够大的文件(比如win下的那个i386文件,好像是这个名字)。物理内存中长期不用的数据,也可以转移到虚拟内存中。这样的交换由OS来控制,用户看起来就好像物理内存大了一样。

虚拟内存寻址的一个好处就是可以使进程使用很大的虚拟内存地址,而无需考虑实际的物理内存的大小。这使得进程内存可以基于使用需要,从逻辑上分为几个不同段。这些段可能映射到不连续的虚拟内存地址上,以使内存能够增加。

为了共享RAM,需要有一个叫做交换磁盘(swap disk)的特殊磁盘空间。交换磁盘的重要目的是保存程序的通过LRU算法换出的内存,这样可以使很多程序能够共享有限的RAM。一旦非活动程序的RAM页被写入交换磁盘(Page Out),操作系统可以使空出来的内存用于其他活动的程序。如果非活动程序稍后又继续执行,被page out的RAM页又重新从交换磁盘中载入RAM(Page in)。这种重新载入RAM页的动作就叫交换,而交换是非常消耗时间的,并且会降低相关程序的性能。

尽管交换磁盘确保并发的RAM使用量能大于实际的RAM总理,但是为了确保最佳性能,交换空间绝不要被活动程序所使用。这是因为从交换磁盘上读取page out的RAM页要比直接从RAM中读取内存页要慢14000倍。磁盘访问都是以毫秒记的,而RAM访问是以10亿份之一秒记的。

2.1.1.Oracle的内存段类型

段(Segement)在OS上是对不同内存的使用目的和存放位置不同的区分。和一般的程序一样,Oracle使用以下几种段类型:

o程序文本(Pragram Text)

文本段包括了程序本身的可执行的机器代码(除动态链接库以外)。文本段一般标识为只读,因此它能被多个进程共享来跑同一个程序。

o初始化全局数据(Initialized Global Data)

这一段包括了被编译器初始化的全局数据,比如用于跟踪数据的字符串。初始化数据能被修改,因此它不能被运行同一程序的多个进程共享。Oracle很少使用这个段。

o未初始化全局数据(Uninitialized Global Data)

未初始化全局数据一般称为BSS(Block Started bySymbol 以符号开始的块)段。这一段包括了静态分配的全局数据,这些数据在进程运行时被进程初始化。Oracle也很少使用这个段。

o数据堆(Data Heap)

数据堆被用于进程在运行时,通过使用系统调用malloc()或sbrk()动态分配内存。Oracle将数据heap用于PGA。

o执行堆栈(Execution Stack)

无论什么时候一个函数被调用,它的参数和返回上下文被push到一个执行堆栈中。返回上下文实际上是一组CPU注册值,这些注册值描述了进程在调用函数时那一刻的状态。当调用结束后,堆栈被POP而上下文被保留,以使执行能从函数调用时的结构状态立即执行下去。堆栈同时还保留了代码块的本地变量。堆栈大小依赖于函数嵌套或递归调用的深度、参数和本地变量所需的内存大小。

o共享库(Shared Libraries)

共享库是一个与位置无关的可执行代码集,这个集合实现了许多程序――特别是系统调用功能――所需要的功能。共享库段也是只读的,它被所有的进程(包括Oracle进程)共享。共享库无需保存一份在内存中。当调用了共享库中的一个函数后,进程需要打开共享库文件,然后通过系统调用mmap()将它映射到它的地址空间去。

使用共享库的另外一种方法是在程序文本段本身将需要的系统调用include进去。在那些不支持共享库的操作系统中或用上面方式有问题时就需要这样做。在大多数操作系统中,Oracle使用共享库作为来实现系统调用而不是实现Oracle代码本身。然而,Java类库都是编译好的,并且作为共享库动态链接的。

o共享内存段(Shared Memory Segment)

共享内存允许关联的进程共同读写内存中的同样数据。每个需要在共享内存段中寻址的进程都需要先将这段内存附到它自己的虚拟内存地址中去(一般通过shmat()系统调用实现)。Oracle SGA就是使用的共享内存段。

2.1.2.Oracle的内存管理模块

Oracle中有两个内存管理模块。一个是内核服务内存管理模块(KernelService Memory KSM);一个是内核通用堆管理模块(Kernel Generic Heap KGH)

在X$表中,有两种用于这两个模块的表,它们就是以KSM和KGH开头的表。这两个模块相互非常紧密。内存管理模块是负责与操作系统进行接口以获取用于Oracle的内存,同时还负责静态内存的分配。这个模块中比较重要的X$表是X$ksmfs,它记录了固定sga、buffer cache、log buffer在内核服务内存中的分配。而堆管理模块则负责动态内存的管理。这也就是为什么SGA和PGA中堆又叫可变内存区了。SharedPool、Library cache和PGA的堆都是由这个模块管理的。

一个堆(Heap)包括一个堆描述符和一个或多个内存扩展段(extent)。一个堆还可以包含子堆(Subheap)。这种情况下,堆描述符和子堆的扩展段可以被视为其父堆的大块(chunk)。堆描述符的大小依赖于堆的类型和堆的空闲列表和LRU列表所包含的列表(Header)头的多少。一个扩展段又一个包含指向前一个和后一个扩展段指针(Pointer)的小的头部,扩展段的其他内存就是堆可用于动态分配的内存。

除了还包含一个保留列表的这一特性外,Shared Pool中的子堆具有与Shared Pool本身相同的结构。内存是以Chunk为单位分配的。空闲的chunk按照大小来组织在相应的空闲列表(Free List)中。而未pin住的、可重建(unpinned recreatable)的chuck被维护在两个分别用于周期性chunk和短期chunk的LRU链表中。子堆还有一个包含少许空闲内存的主永久内存chunk。子堆也许还包含子堆,一共可以嵌套到四层。

子堆的概念非常重要,因为大多数被缓存在shared pool中的对象实际上都被保存在子堆中,而不是保存在最上一层的堆中。在一个子堆中寻找空闲空间就相当于在shared pool中寻