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




