摘要:Oracle內(nèi)存的管理比較復(fù)雜,但對(duì)提高Oracle的性能來(lái)說(shuō)是非常重要的,也是很多數(shù)據(jù)庫(kù)管理人員需要花費(fèi)大量時(shí)間去研究的問題。內(nèi)存的配置是影響Oracle性能的重要問題,值得引起我們的重視。主要介紹oracle內(nèi)存管理的內(nèi)容。
關(guān)鍵詞:oracle;內(nèi)存管理;內(nèi)存分配;回收
中圖分類號(hào):C931文獻(xiàn)標(biāo)志碼:A文章編號(hào):1673-291X(2010)33-0209-02
要了解內(nèi)存管理,首先需要知道虛擬內(nèi)存,更要知道CPU尋址。在CPU中,所有一切都是二進(jìn)制表示的,32位CPU的尋址范圍是4G。但一臺(tái)機(jī)器的實(shí)際物理內(nèi)存可能只有2G。這時(shí),操作系統(tǒng)就提出了一個(gè)虛擬內(nèi)存的概念,如果所尋址的數(shù)據(jù)實(shí)際上不在物理內(nèi)存中,那就從虛擬內(nèi)存中來(lái)獲取。這個(gè)虛擬內(nèi)存可以是一個(gè)專門文件格式的磁盤分區(qū),也可以是硬盤上的某個(gè)足夠大的文件。
一、Oracle內(nèi)存管理
虛擬內(nèi)存尋址的一個(gè)好處就是可以使進(jìn)程使用很大的虛擬內(nèi)存地址,而無(wú)須考慮實(shí)際的物理內(nèi)存的大小。這使得進(jìn)程內(nèi)存可以基于使用需要,從邏輯上分為幾個(gè)不同段。這些段可能映射到不連續(xù)的虛擬內(nèi)存地址上,以使內(nèi)存能夠增加。
1.Oracle的內(nèi)存段類型
段在操作系統(tǒng)上是對(duì)不同內(nèi)存的使用目的和存放位置不同的區(qū)分。Oracle使用以下幾種段類型:(1)程序文本。文本段包括了程序本身的可執(zhí)行的機(jī)器代碼。文本段一般標(biāo)識(shí)為只讀,因此它能被多個(gè)進(jìn)程共享來(lái)跑同一個(gè)程序。(2)數(shù)據(jù)堆。數(shù)據(jù)堆被用于進(jìn)程在運(yùn)行時(shí),通過(guò)使用系統(tǒng)調(diào)用動(dòng)態(tài)分配內(nèi)存。(3)執(zhí)行堆棧。當(dāng)一個(gè)函數(shù)被調(diào)用時(shí),它的參數(shù)和返回上下文被壓入一個(gè)執(zhí)行堆棧中。返回上下文實(shí)際上是一組CPU注冊(cè)值,這些注冊(cè)值描述了進(jìn)程在調(diào)用函數(shù)時(shí)那一刻的狀態(tài)。堆棧同時(shí)還保留了代碼塊的本地變量。(4)共享庫(kù)。共享庫(kù)是一個(gè)與位置無(wú)關(guān)的可執(zhí)行代碼集,這個(gè)集合實(shí)現(xiàn)了許多程序特別是系統(tǒng)調(diào)用功能。共享庫(kù)段也是只讀的,它被所有的進(jìn)程共享。(5)共享內(nèi)存段。共享內(nèi)存允許關(guān)聯(lián)的進(jìn)程共同讀寫內(nèi)存中的同樣數(shù)據(jù)。每個(gè)需要在共享內(nèi)存段中尋址的進(jìn)程都需要先將這段內(nèi)存附到它自己的虛擬內(nèi)存地址中去。
2.Oracle的內(nèi)存管理模塊
Oracle中有兩個(gè)內(nèi)存管理模塊。一個(gè)是內(nèi)核服務(wù)內(nèi)存管理模塊;一個(gè)是內(nèi)核通用堆管理模塊。內(nèi)存管理模塊是負(fù)責(zé)與操作系統(tǒng)進(jìn)行接口以獲取用于Oracle的內(nèi)存,同時(shí)還負(fù)責(zé)靜態(tài)內(nèi)存的分配。而堆管理模塊則負(fù)責(zé)動(dòng)態(tài)內(nèi)存的管理。這也就是為什么SGA和PGA中堆又叫可變內(nèi)存區(qū)了。共享池、庫(kù)緩存和程序全局區(qū)的堆都是由這個(gè)模塊管理的。
3.內(nèi)存分配顆粒
在Oracle的內(nèi)存分配和管理中,有一個(gè)重要的單位:顆粒(Granule)。顆粒是連續(xù)虛擬內(nèi)存分配的單位。在實(shí)例啟動(dòng)時(shí),Oracle先分配顆粒條目,使所有顆粒能支持到最大系統(tǒng)全局區(qū)的空間大小。如果沒有設(shè)置PRE_PAGE_SGA和LOCK_SGA,在實(shí)例啟動(dòng)時(shí),每個(gè)組件請(qǐng)求它所需要的最少顆粒??梢酝ㄟ^(guò)ALERT SYSTEM命令來(lái)修改分配給各個(gè)組件的顆粒數(shù)。當(dāng)想要給組件增加顆粒時(shí),需要考慮實(shí)例中是否還有足夠的顆粒來(lái)分配給新增加的組件大小。ALERT SYSTEM指定的是新的組件大小,是內(nèi)存的大小,不是顆粒數(shù)。而Oracle在分配內(nèi)存時(shí),會(huì)以顆粒為單位,如果新分配的大小不是顆粒大小的倍數(shù),則會(huì)使用最接近且大于分配數(shù)的顆粒的倍數(shù)值。
4.系統(tǒng)全局區(qū)內(nèi)存
當(dāng)一個(gè)Oracle實(shí)例啟動(dòng)后,主要的系統(tǒng)全局區(qū)的大小一開始基于初始化參數(shù)計(jì)算得出。這些大小可以通過(guò)show sga顯示。但是,在共享內(nèi)存段分配之前,每個(gè)區(qū)的大小都只有大概一個(gè)內(nèi)存頁(yè)大小。當(dāng)需要時(shí),這些區(qū)被分為一些子區(qū),因此沒有一個(gè)子區(qū)會(huì)大于操作系統(tǒng)所限制的共享內(nèi)存段的大小。對(duì)于可變區(qū),有一個(gè)操作系統(tǒng)規(guī)定的最小子區(qū)大小,因此可變區(qū)的大小是最小子區(qū)大小的倍數(shù)。
如果可能,Oracle會(huì)為整個(gè)系統(tǒng)全局區(qū)分配一個(gè)單獨(dú)的共享內(nèi)存段。然而,如果系統(tǒng)全局區(qū)大于操作系統(tǒng)限制的單個(gè)共享內(nèi)存段的大小時(shí),Oracle會(huì)使用最佳的算法來(lái)將所有子區(qū)組織在多個(gè)共享段中,并且不超過(guò)系統(tǒng)全局區(qū)最大大小的限制。
嚴(yán)重的頁(yè)入/頁(yè)出會(huì)導(dǎo)致很嚴(yán)重的系統(tǒng)性能問題。然而,大內(nèi)存消耗導(dǎo)致的間斷的頁(yè)入/頁(yè)出是沒有影響的。大多數(shù)系統(tǒng)都有大量的非活動(dòng)內(nèi)存被頁(yè)出而沒有什么性能影響。但少量的頁(yè)出也是有問題的,因?yàn)檫@會(huì)導(dǎo)致系統(tǒng)全局區(qū)中那些中度活性的頁(yè)會(huì)經(jīng)常頁(yè)出。大多數(shù)操作系統(tǒng)提供了一個(gè)讓Oracle鎖住系統(tǒng)全局區(qū)到物理內(nèi)存中的機(jī)制以防止頁(yè)出。在某些操作系統(tǒng)中,oracle需要有特定的系統(tǒng)權(quán)限來(lái)使用這一特性。
5.進(jìn)程內(nèi)存
進(jìn)程包括程序代碼、本地?cái)?shù)據(jù)域和系統(tǒng)全局區(qū)。程序代碼的大小由基本內(nèi)核、內(nèi)核、聯(lián)機(jī)的網(wǎng)絡(luò)情況以及所使用的操作系統(tǒng)決定的。系統(tǒng)全局區(qū)大小是由Oracle初始化參數(shù)決定的。而這兩部分是共享。隨著用戶的增加,它們與單個(gè)Oracle服務(wù)進(jìn)程的關(guān)系越來(lái)越小。它們是可以通過(guò)修改Oracle配置參數(shù)來(lái)改變的。
本地?cái)?shù)據(jù)域中的堆棧是根據(jù)需要來(lái)增大、縮小的。然而,堆就不會(huì)釋放內(nèi)存了。堆的主要組成部分是程序全局區(qū)。而影響程序全局區(qū)的主要因素是排序區(qū)大小。因此,非自動(dòng)程序全局區(qū)內(nèi)存管理模式下,可以通過(guò)控制排序區(qū)大小來(lái)控制程序全局區(qū)的大小??偟膩?lái)說(shuō),可以有以下方法來(lái)限制進(jìn)程內(nèi)存大小:(1)降低相關(guān)的內(nèi)核參數(shù);(2)通過(guò)Oracle參數(shù)來(lái)降低系統(tǒng)全局區(qū);(3)通過(guò)減小排序區(qū)大小來(lái)降低程序全局區(qū)。
二、Oracle的內(nèi)存的分配與回收
Oracle中的共享內(nèi)存區(qū)的分配都是以大塊(chunk)為最小單位的。大塊不是一個(gè)固定值,它是一個(gè)擴(kuò)展段中一塊連續(xù)的內(nèi)存。而Oracle的內(nèi)存的增長(zhǎng)是以擴(kuò)展段為基礎(chǔ)的。
1.空閑內(nèi)存分配和回收
空閑內(nèi)存都是由空閑列表統(tǒng)一管理、分配的。每個(gè)空閑的大塊都會(huì)屬于也只屬于一個(gè)空閑列表??臻e列表上的大塊的大小范圍是由桶(bucket)來(lái)劃分的。我們也可以把桶視為一種索引,使Oracle在查找空閑塊時(shí),先定位所需的空閑塊在哪個(gè)桶的范圍內(nèi),然后在相應(yīng)的空閑列表中查找。
一次內(nèi)存的分配過(guò)程如下:當(dāng)一個(gè)進(jìn)程需要一個(gè)內(nèi)存的大塊時(shí),它會(huì)先掃描目標(biāo)空閑列表以查找最適合大小的大塊。如果找不到一個(gè)大小正好合適的大塊,則繼續(xù)掃描空閑列表中更大的大塊。如果找到的可用大塊比所需的大小大24字節(jié)或者更多,則這個(gè)大塊就會(huì)被分裂,剩余的空閑大塊又被加到空閑列表的合適位置。如果空閑列表中沒有一個(gè)大塊能滿足要求的大小,則會(huì)從非空的相鄰?fù)暗目臻e列表中取最小的大塊。如果所有空閑列表都是空的,就需要掃描LRU鏈表釋放最近最少使用的內(nèi)存。當(dāng)大塊空閑時(shí),如果相鄰的大塊也是空閑的,它們可能會(huì)結(jié)合起來(lái)。
2.共享池的分配和回收
在共享池中,空閑列表掃描、管理和大塊分配的操作都是受到shared pool latch保護(hù)的。顯然,如果共享池含有大量的非常小的空閑大塊,則掃描空閑列表時(shí)間將很長(zhǎng),而shared pool latch則會(huì)要保持很久。這就是導(dǎo)致shared pool latch爭(zhēng)用的主要原因了??梢圆扇≡趯?shí)例啟動(dòng)時(shí)制止住那些可能會(huì)斷斷續(xù)續(xù)使用的對(duì)象。
實(shí)際上,oracle實(shí)例啟動(dòng)時(shí),會(huì)保留大概一半的共享池,當(dāng)有內(nèi)存壓力時(shí)逐漸釋放它們。Oracle通過(guò)這種方法限制碎片的產(chǎn)生。Oracle的少量空襲內(nèi)存和X$表即其他持久內(nèi)存結(jié)構(gòu)一起,隱含在共享池的主要持久內(nèi)存大塊中。這些內(nèi)存不在共享池的空閑列表中,因此能夠立即被分配。
3.SGA的分配
當(dāng)實(shí)例啟動(dòng)時(shí),oracle在虛擬內(nèi)存地址空間中創(chuàng)建一段連續(xù)的內(nèi)存區(qū),這個(gè)內(nèi)存區(qū)的大小與系統(tǒng)全局區(qū)所有區(qū)相關(guān)參數(shù)有關(guān)。通過(guò)調(diào)用Win32 API接口VirtualAlloc,在接口函數(shù)的參數(shù)中指定MEM_RESERVE|MEM_COMMIT內(nèi)存分配標(biāo)識(shí)和PAGE_READWRITE保護(hù)標(biāo)識(shí),這部分內(nèi)存始終會(huì)被保留和提交。這就保證所有線程都能訪問這塊內(nèi)存,并且這塊內(nèi)存區(qū)始終有物理存儲(chǔ)所支持。
當(dāng)一個(gè)進(jìn)程創(chuàng)建后,Windows NT會(huì)在進(jìn)程的地址空間中創(chuàng)建一個(gè)堆,這個(gè)堆被稱為進(jìn)程的默認(rèn)堆。許多Win32 API調(diào)用接口和C運(yùn)行調(diào)用接口都會(huì)使用這個(gè)默認(rèn)堆。當(dāng)需要時(shí),進(jìn)程能在虛擬內(nèi)存地址空間中創(chuàng)建另外的命名堆。默認(rèn)堆創(chuàng)建為1M大小的內(nèi)存區(qū),當(dāng)執(zhí)行分配或釋放這個(gè)堆的操作時(shí),堆管理器提交或撤銷這個(gè)區(qū)。而訪問這個(gè)區(qū)是通過(guò)臨界區(qū)來(lái)串行訪問的,所以多個(gè)線程不能同時(shí)訪問這個(gè)區(qū)。
4.會(huì)話內(nèi)存的分配
當(dāng)監(jiān)聽創(chuàng)建了一個(gè)用戶會(huì)話時(shí),Oracle服務(wù)進(jìn)程就通過(guò)調(diào)用Win32 API函數(shù)創(chuàng)建用戶連接所必須的內(nèi)存結(jié)構(gòu),并且指定MEM_RESERVE|MEM_COMMIT標(biāo)識(shí),以保持和提交給線程私有的地址空間區(qū)域。用戶會(huì)話在分配程序全局區(qū)、用戶全局區(qū)和調(diào)用全局區(qū)時(shí)同時(shí)也遵循64K的最小粒度,來(lái)提交倍數(shù)于這個(gè)粒度值的內(nèi)存頁(yè)。
三、結(jié)束語(yǔ)
Oracle內(nèi)存的管理比較復(fù)雜,但對(duì)提高Oracle的性能來(lái)說(shuō)是非常重要的,也是很多數(shù)據(jù)庫(kù)管理人員需要花費(fèi)大量時(shí)間去研究的問題。
參考文獻(xiàn):
[1]Fuyuncat.Oracle內(nèi)存全面分析[EB/OL].www.HelloDBA.com.
[責(zé)任編輯 郭偉]