深入SQL SERVER 2000的內(nèi)存管理機(jī)制(三)
內(nèi)存區(qū)域
SQL Server是分2塊區(qū)域來(lái)組織內(nèi)存分配,分別是Bpool (緩沖池區(qū))和MemToLeave (內(nèi)存釋放區(qū)),如果你使用AWE內(nèi)存,那么實(shí)際上有第三個(gè)區(qū):Windows AWE支持的高于3GB的物理內(nèi)存區(qū)。
緩沖池區(qū)是這3塊內(nèi)存區(qū)中最卓越的,是SQL SERVER最初分配的緩沖池供最初的數(shù)據(jù)頁(yè)和索引頁(yè)使用,并且被用來(lái)分配小于8K的內(nèi)存。MemToLeave 是由虛擬內(nèi)存空間組成包括在用戶(hù)內(nèi)存空間沒(méi)有被緩沖池區(qū)使用的內(nèi)存空間之中。Windows AWE調(diào)用3GB以上內(nèi)存空間的函數(shù)作為緩沖池區(qū)的擴(kuò)展可以提供額外的內(nèi)存空間緩存數(shù)據(jù)頁(yè)和索引頁(yè)。
當(dāng)你啟動(dòng)SQL SERVER時(shí),緩沖池區(qū)的上限是根據(jù)機(jī)器中物理內(nèi)存推算或用戶(hù)內(nèi)存空間的大小。一旦緩沖池區(qū)的大小被確定,內(nèi)存釋放區(qū)就緊隨其后,不至于被后面的緩沖池區(qū)保留部分劃分成分散的碎片。然后緩沖池區(qū)又在內(nèi)存釋放區(qū)旁邊,使用32塊單獨(dú)的保留區(qū)運(yùn)行DLL文件和其他在緩沖池區(qū)被預(yù)定時(shí)SQL SERVER中使用的虛擬內(nèi)存空間。當(dāng)緩沖池區(qū)被預(yù)留后,內(nèi)存釋放區(qū)被釋放。這段區(qū)域被SQL SERVER內(nèi)部用來(lái)擴(kuò)展8K的數(shù)據(jù)頁(yè)和分配給其他外部應(yīng)用(就像:內(nèi)存消費(fèi)者是SQL SERVER主要引擎以外的SQL SERVER進(jìn)程),比如:OLE DB providers,COM對(duì)象等等.
因此,當(dāng)SQL SERVER已經(jīng)啟動(dòng), Bpool (緩沖池區(qū))就被預(yù)留,但不提交,同時(shí)在該進(jìn)程在虛擬內(nèi)存空間內(nèi)的MemToLeave (內(nèi)存釋放區(qū))其實(shí)是空閑區(qū)域.如果你通過(guò)性能分析器的 Virtual Bytes Perform 計(jì)數(shù)器,在SQL Server啟動(dòng)后看SQL SERVER的進(jìn)程,你會(huì)看到它可以反映Bpool (緩沖池區(qū))預(yù)留區(qū).我看到人們有些驚慌,因?yàn)檫@個(gè)數(shù)值比較高—畢竟,它反映的不是本機(jī)器的總共物理內(nèi)存就是最大的用戶(hù)內(nèi)存空間減去MemToLeave (內(nèi)存釋放區(qū)).這是不用擔(dān)心的,比較而言這只是保留區(qū),沒(méi)有提交的空間.就如我前面所述,保留空間只是地址空間—并沒(méi)有真實(shí)的物理內(nèi)存存儲(chǔ)直到內(nèi)存空間被提交. 隨著時(shí)間的過(guò)去,內(nèi)存空間被提交,Bpool (緩沖池區(qū))將會(huì)增加,知道該SERVER原始啟動(dòng)時(shí)確定的上限.
監(jiān)控SQL Server虛擬內(nèi)存的使用
你可以通過(guò) SQL Server:Buffer Manager\Target Pages Perform計(jì)數(shù)器跟蹤Bpool (緩沖池區(qū))確定的最大空間.因?yàn)?/span>SERVER不同的部分需要內(nèi)存, Bpool (緩沖池區(qū))提交8K大小的頁(yè)(這是原始保留的直到提交的大小到達(dá)確定目標(biāo)).你可以通過(guò) SQL Server:Buffer Manager\Total Pages Perform計(jì)數(shù)器跟蹤Bpool (緩沖池區(qū))使用的提交虛擬內(nèi)存, 你可以通過(guò) Pivate Bytes計(jì)數(shù)器跟蹤SQL Server進(jìn)程使用的全部提交的虛擬內(nèi)存.
因?yàn)?/span>, 大部分的SQL Server的虛擬內(nèi)存的使用是來(lái)自于Bpool (緩沖池區(qū)),通過(guò)上面2個(gè)計(jì)數(shù)器可以知道. 一般而言增長(zhǎng)和平穩(wěn)是一前一后地.(請(qǐng)牢記:當(dāng)應(yīng)用程序啟動(dòng)了對(duì)AWE的支持, Pivate Bytes計(jì)數(shù)器不能反映總體SQL Server內(nèi)存使用情況).如果Total Pages Perform計(jì)數(shù)器是水平的而Pivate Bytes計(jì)數(shù)器是向上傾斜的,這一般表示正在從MemToLeave (內(nèi)存釋放區(qū))分配新的內(nèi)存.這個(gè)分配過(guò)程會(huì)正常結(jié)束—例如:在SERVER中分配相關(guān)聯(lián)的線(xiàn)程堆棧作為附加的工作線(xiàn)程,這也有可能是一個(gè)內(nèi)部測(cè)COM對(duì)象或XPROC的內(nèi)存泄漏.如果一個(gè)程序因?yàn)?strong>MemToLeave (內(nèi)存釋放區(qū))耗盡而用完虛擬內(nèi)存空間,這是由于內(nèi)存泄漏或內(nèi)存過(guò)度消費(fèi).(或者在MemToLeave (內(nèi)存釋放區(qū))中最大空閑塊降低到默認(rèn)線(xiàn)程堆棧0.5MB以下),這樣SERVER就不能產(chǎn)生新的工作線(xiàn)程,即使在sp_configure max worker threads 的值沒(méi)有到.在這種情況下,如果SERVER需要產(chǎn)生新的工作線(xiàn)程來(lái)執(zhí)行一個(gè)工作請(qǐng)求—比如:處理一個(gè)對(duì)SERVER的新的連接請(qǐng)求,這些工作將會(huì)延遲,直到SERVER可以產(chǎn)生新的線(xiàn)程或其他的線(xiàn)程可以使用.這樣,在有足夠的MemToLeave (內(nèi)存釋放區(qū))釋放或其他的工作線(xiàn)程可以有效的處理連接之前,系統(tǒng)會(huì)阻止一個(gè)用戶(hù)連接到SERVER,因?yàn)檫@個(gè)連接會(huì)超時(shí)中止(time out).
內(nèi)存分配器
在SERVER中一個(gè)內(nèi)存的消費(fèi)者初始化一個(gè)內(nèi)存分配器,首先是產(chǎn)生一個(gè)內(nèi)存對(duì)象來(lái)管理這些請(qǐng)求.當(dāng)這個(gè)對(duì)象來(lái)分配這些請(qǐng)求,他在SERVER的內(nèi)存管理器中,從Bpool (緩沖池區(qū))或MemToLeave (內(nèi)存釋放區(qū))來(lái)履行這些請(qǐng)求.如果這些請(qǐng)求小于8K,這些請(qǐng)求通常在Bpool (緩沖池區(qū)) 分配.如果請(qǐng)求需要8K或以上的內(nèi)存空間, 這些請(qǐng)求通常在MemToLeave (內(nèi)存釋放區(qū))分配.因?yàn)橐粋€(gè)單獨(dú)的內(nèi)存對(duì)象可以用來(lái)執(zhí)行多次內(nèi)存分配.所以有可能一次內(nèi)存分配正好在8K以下(包括管理對(duì)象的消費(fèi))的請(qǐng)求被分配在MemToLeave (內(nèi)存釋放區(qū)). 在SQL Server的處理空間中,內(nèi)存消費(fèi)者通常是內(nèi)部的.換句話(huà)說(shuō),這些內(nèi)存消費(fèi)者和對(duì)象是SQL Server自己的規(guī)范需要消耗內(nèi)存來(lái)執(zhí)行任務(wù),但也不一定都這樣.也存在一些外部的消費(fèi)者,就像我前面鎖說(shuō)的.通常,這些外部的內(nèi)存消費(fèi)者調(diào)用正常的Win32 API內(nèi)存函數(shù)來(lái)分配和管理內(nèi)存,并且從MemToLeave (內(nèi)存釋放區(qū))分配內(nèi)存空間,非常明顯這是SQL Server程序中唯一有效的區(qū)域. 可是XPROCS有特殊的異常處理,當(dāng)一個(gè)xproc調(diào)用Open Data Services(ODS) srv_alloc API函數(shù),這完全和其他的內(nèi)存消費(fèi)者一樣. 一般而言srv_alloc API函數(shù)從Bpool (緩沖池區(qū))申請(qǐng)小于8K的內(nèi)存,對(duì)于大的內(nèi)存從MemToLeave (內(nèi)存釋放區(qū))分配.
內(nèi)存管理者
當(dāng)SERVER運(yùn)行時(shí),內(nèi)存管理者檢查物理內(nèi)存的剩余有效容量,以保證WINDOWS和其他的應(yīng)用程序可以可以平穩(wěn)的運(yùn)行.這個(gè)有效內(nèi)存的大小在4MB和10MB直接變化.(在WINDOWS 2003中更接近10MB)并且這個(gè)基于系統(tǒng)內(nèi)核加載和Bpool (緩沖池區(qū))中的頁(yè)生命周期.如果SERVER上的有效物理內(nèi)存空間在這個(gè)閥值以下,SERVER會(huì)減少提交Bpool (緩沖池區(qū))頁(yè)來(lái)收縮內(nèi)存物理存儲(chǔ)的使用(假設(shè)動(dòng)態(tài)內(nèi)存分配是激活的).內(nèi)存管理者也保證提交的內(nèi)存頁(yè)在指定的時(shí)間點(diǎn)后空閑,這樣在接受到一個(gè)新的分配請(qǐng)求時(shí),就不再需要等待內(nèi)存分配.通過(guò)”空閑”,我的意思是:內(nèi)存頁(yè)提交后,但沒(méi)有被使用.沒(méi)有使用的提交Bpool (緩沖池區(qū))頁(yè)可以通過(guò)一個(gè)空閑頁(yè)清單來(lái)跟蹤.這樣所有得新得頁(yè)都來(lái)自空閑頁(yè)清單, 內(nèi)存管理者從Bpool (緩沖池區(qū))預(yù)留區(qū)提交更多得頁(yè)直到全部得預(yù)留區(qū)被提交.你看:Process:Private Bytes Perfmon 計(jì)數(shù)器緩慢增長(zhǎng)(通常是成直線(xiàn)的)就是這個(gè)原因.
在多CPU系統(tǒng)中,沒(méi)一個(gè)都有自己?jiǎn)为?dú)的空閑頁(yè)清單,當(dāng)一個(gè)空閑頁(yè)被要求響應(yīng)一個(gè)應(yīng)用程序的請(qǐng)求,首先在當(dāng)前的CPU的空閑頁(yè)清單中滿(mǎn)足分配的空間被檢查,然后是其他CPU的空閑頁(yè)清單.這樣更好的利用每個(gè)處理器的本地緩存,提高了在多處理器的SERVER上提高穩(wěn)定性.你可以通過(guò)SQL Server:Buffer Partition Perform對(duì)象監(jiān)視指定的Bpool (緩沖池區(qū))區(qū),你可以可以通過(guò)SQL Server:Buffer Manager\Free Pages Perform計(jì)數(shù)器監(jiān)視所有的Bpool (緩沖池區(qū))區(qū).
因此在SQL SERVER整個(gè)運(yùn)行過(guò)程中,SQL SERVER的內(nèi)存處理器(無(wú)論內(nèi)存線(xiàn)程管理器或同其他的線(xiàn)程服務(wù))監(jiān)視系統(tǒng)的內(nèi)存使用狀態(tài),確認(rèn)合理的剩余空閑物理內(nèi)存的數(shù)量給其他的系統(tǒng)和預(yù)留合理的空閑頁(yè)響應(yīng)新的內(nèi)存請(qǐng)求.當(dāng)SERVER使用AWE內(nèi)存,有些內(nèi)存狀態(tài)必需改變. Bpool (緩沖池區(qū))區(qū)開(kāi)始通過(guò)SERVER的物理內(nèi)存中獲得和鎖定內(nèi)存,內(nèi)存鎖的數(shù)量的變化是根據(jù)服務(wù)器最大內(nèi)存是否設(shè)置了.如果配置了, Bpool (緩沖池區(qū))區(qū)試圖根據(jù)最大的服務(wù)器內(nèi)存鎖住相應(yīng)數(shù)量的內(nèi)存.如果沒(méi)有配置, Bpool (緩沖池區(qū))區(qū)會(huì)鎖住接近128MB內(nèi)存的所有物理內(nèi)存,只有少量的區(qū)域留給其他處理.然后Bpool (緩沖池區(qū))區(qū)使用高于3G的物理內(nèi)存(AWE內(nèi)存)用作運(yùn)行數(shù)據(jù)和索引的頁(yè)文件. Bpool (緩沖池區(qū))區(qū)根據(jù)需要映射物理內(nèi)存和虛擬內(nèi)存,因此可以被32位的指針引用.
概述
你已經(jīng)知道了:SQL Server內(nèi)存管理器是一個(gè)難點(diǎn).理解一個(gè)程序是如何分配和管理內(nèi)存是了解一個(gè)程序如何工作的基礎(chǔ).內(nèi)存是非常重要的資源,它的有效利用是一個(gè)可靠應(yīng)用程序設(shè)計(jì)的基本因素,懂得一個(gè)應(yīng)用程序內(nèi)存管理機(jī)制會(huì)是你的程序設(shè)計(jì)如虎添翼.
一個(gè)開(kāi)發(fā)者,他是如何影響你呢?理解SERVER的內(nèi)存管理機(jī)制賦予你如何寫(xiě)一個(gè)高效的應(yīng)用程序和解決一些和內(nèi)存相關(guān)聯(lián)問(wèn)題的洞察力. 比如說(shuō),在一個(gè)提高客戶(hù)端連接速度的調(diào)試中,你提高SQL Server的默認(rèn)網(wǎng)絡(luò)包的大小為8K., 立即,SQL SERVER立刻開(kāi)始在ERROR LOG中寫(xiě)錯(cuò)誤信息,提示預(yù)留虛擬內(nèi)存在MemToLeave (內(nèi)存釋放區(qū))區(qū)有問(wèn)題.在看到這樣的信息后你立刻會(huì)知道這個(gè)改變至少是問(wèn)題的一部分,因?yàn)槟阒婪峙?/span>8K或更多的內(nèi)存是在MemToLeave (內(nèi)存釋放區(qū))區(qū). 這樣SQL Server連接相關(guān)聯(lián)的緩存也是來(lái)自這個(gè)區(qū)域,因?yàn)槟阋呀?jīng)配置網(wǎng)絡(luò)包的大小太高了.配置默認(rèn)的網(wǎng)絡(luò)包適合于.NET framework的SQLClinet Provider 8KB.這種情況并不象聽(tīng)起來(lái)那么合理.實(shí)際上,這是非常常見(jiàn)的問(wèn)題,由于MemToLeave (內(nèi)存釋放區(qū))缺乏內(nèi)存空間而引起的,因?yàn)榫W(wǎng)絡(luò)包的大小太大,至少有些部分是這樣的.
同時(shí),了解SQL Server劃分內(nèi)存的方法可以幫助你了解你定制在SQL Server中運(yùn)行的代碼是否在系統(tǒng)資源的臨界值,比如數(shù)據(jù)緩存. 比如說(shuō),你建立一個(gè)擴(kuò)展存儲(chǔ)過(guò)程調(diào)用SRV_PRO()函數(shù)來(lái)分配內(nèi)存.假設(shè),暫時(shí)你代碼中分配的緩存小于8KB.根據(jù)我們前面的討論,我們知道擴(kuò)展存儲(chǔ)過(guò)程是從Bpool (緩沖池區(qū))來(lái)分配內(nèi)存.—可以用作數(shù)據(jù)緩存.
了解SQL Server是如何管理內(nèi)存的,可以幫助我們按大小排列系統(tǒng)的開(kāi)始順序.這可以幫助你計(jì)算你所需的物理內(nèi)存的數(shù)量和如何分配和分區(qū)給SQL SERVER.比如:良好的理解AWE