探索系列——神人steve adams之著oracle8i interal service(十九)

wisdomone1發表於2010-05-10
       一些os專門為一些特定型別的segments保留某些虛擬地址範圍.另外一些在虛擬地址空間範圍的邊界或極點(extremities)分配文字,資料,bss segments,
把極點之間的連續的未用地址空間範圍留下來.堆和棧是在這個範圍的對端上面進行分配的,是向中間方向進行增長的.其它一些segments,比如共享記憶體segments,必須
必須位於由程式本身指定stack和heap的一個位置.
       在這樣的一些os中,有時有必要控制sga附加attached在哪個地址上,為了防止這些segments之間的地址空間衝突.在一些情況下,用shared_memory_address和hi_shared_memory_address
引數,但是一些其它的系統,在重新relink資料庫前,有必要使用genksms和在ksms.s檔案中修改附加地址.



intimate shared memory
       一個程式的虛擬地址空間中的每個segment,需要頁表條目,用於支援虛擬到實體地址轉變.如果2個以上的程式對映一個記憶體segment到它們虛擬地址空間的相同位置,從理論上說它們是可以共享相同的頁表條目的.
  這也叫作親密或私密共享記憶體.
       親密共享記憶體在幾個方面會提升效能.特別是,它極大增加了頁表條目的tlb hit rate,因此減少了主記憶體的訪問,較大程度加速了執行速度.對於需要大量共享記憶體和大量程式的例項,它會節省大量的頁表記憶體.
       
       在一些os上,由於沒有替代品,親密共享記憶體會自動用於oracle.在一些情況下,因為os或硬體不支援所以它是不可用.但是,在一些情況下,它與_use_ism引數和共享記憶體segment大小有關.如果在支援精選程式
program-selectable的親密共享程式,_use_ism等於true時,oracle會使用一個標記來從os的它的共享記憶體segments中請求親密共享記憶體.但是,在一些os下,親密共享記憶體只有在segment的頁表具有精確的頁面個數時才可用,
如果這樣的話,會自動使用.比如,對於一個32 bit地址空間和一個4kb的記憶體頁面大小,頁表一個頁面可以定址4mb記憶體.在這種情況下,如果使用了親密共享記憶體,共享記憶體segment必須是4mb的倍數.這樣就可以確保儘量小的調
整shared_pool_size,db_block_buffers,log_buffers引數,然後用oradebug ipc命令檢查sga segments的大小.

       更進一步最佳化地址變化操作,就是允許使用更大尺寸的記憶體頁面大小.比如,你可能使用chatr請求一個針對特定執行程式的用於資料或指令segments的較大的頁面大小.使用一個大頁面減少每個segment所需要的頁表條目數量,
因而提升或加大了segment的tlb hit rate,同時減少了tlb load.oracle在記憶體頁面大小有一些內建的依賴限制,因此請和oracle支援聯絡,在嘗試這樣作之前,使用一個大點的頁面大小是否安全.













sga allocation
        當啟動一個oracle例項,主要的sga區域大小首先根據初始化引數確認它的大小.這些大小會在啟動時顯示報告出來.但是,在分配共享記憶體segments之前,每個區域的大小會四捨五入到一個記憶體頁面的邊界.
這些區域然後分割為子區域,如有必要,以便沒有子區域大於一個共享記憶體segment的相關os限制(unix上針對system v共享記憶體的shmmax).在這種情況下,可變區域,它會取與os相關的最小子區域大小,因此可變區域
大小會四捨五入為最小子區域的倍數.
         如有可能oracle為整個sga分配一個單一的共享記憶體segment.但是,如果sga大於一個單一共享記憶體segment基於os的大小限制,這時oracle會採用一個合適的演算法,把這些子區進行分組為多個共享記憶體segment.


         在oracle7時,sga可變區域必須駐存於連續的記憶體中.因此,如果os不允許oracle虛擬記憶體地址在哪個共享記憶體segment上面附加時,因此會連續附加它們,於是可變segment必須足夠小,把它們放入在一個共享記憶體
segment中.在oracle8不再有這個限制,因為引入了子區域.通常情況下建議提升或加大一個單一共享記憶體segment的大小,為了允許oracle在可能情況下在單一的共享記憶體segment中分配sga.我同意這個建議,但僅僅鑑於可管理性,
例項及程式啟動這個限制區別或差異可以忽略,否則就是0.







paging
          os為sga和它的頁池page pool中為oracle 程式,分配實體記憶體頁.頁池包含所有物理系統記憶體(但不含預留給os本身的).只要一個虛擬記憶體頁面未在實體記憶體中引用,一個頁面就會從頁池的自由列表中分配出來.當記憶體釋放掉時頁面同時
會返回給自由列表的頭部.
          如果自由列表上面的頁頁數量低於一個可設定的門限(在unix system v系統中為lotsfree),這時os開始查詢一些不活躍或不活動的頁面進行頁出page out.如果在某些特定時間內某些頁面沒有被引用過,可以認為它們是不知動的.這些不活動的
頁面會移到自由列表的尾部,但如果它們被修改過,它們的內容必須首先儲存到磁碟.只要自由頁面的個數又返回到門限之上,paging就會停止.


          如果自由列表頁面數目繼續下降,然後os加快paging節奏,以更快速度對一些相關頁面進行不活躍化處理.但是,在一些極端記憶體壓力情況下,有可能大量實體記憶體處於非常活躍狀態,這樣os查詢不活躍頁面就會徒勞無功.這種情況下,一些低優先順序的程式會
被選中且完全被休眠,為了找到不活躍的頁面.雖然os paging行為許多方面是可以調節的,但這種調節作用不大或不明顯.

          大量paging活動會對系統效能造成極大的影響.但是,大量使用或佔用記憶體附加有斷斷續續的paging並不用過分關注.大多系統有足夠的不活躍記憶體可以被頁出,它們對於系統效能影響很小或者沒有.但是,如果發現一直有light paging,這就要引起注意了,因為
sga中一些適度的活動頁面將會重複被頁出.大多os具備這種機制,保證oracle把sga鎖定在實體記憶體中,防止它發生paging.如果一直發現paging就要設定lock_sga為true.

          那麼如何確定os是否發生paging,如果發生paging了,paging是一直在發生呢或者嚴重嗎?如果你有足夠的空閒記憶體,系統不會存在paging.如果自由記憶體不足,可以檢視每秒頁出的頁面數.這個度量值可以在winnt下檢視效能監控器,或在unix中查閱vmstat.
如果這個值為非0,系統一直處於paging,sga如有可能應被固定到實體記憶體.這尤其適用於一個paged file system buffer cache的os,如:nt 和solaris.


          但是也要注意,頁出比率並不代表os(帶有一個paged buffer cache)paging 活動的強度.因為buffered file system writes是由paging subsystem來處理,因而這樣就會增大或誇大頁出比率.掃描比率可以很好說明或表明這種系統的paging 活動強度.掃描比率
當查詢不活躍頁面時,每秒查詢的頁面數量.scan rate透過vmstat的sr列顯示出來.如果低於10pages/s就認為paging是light輕微的.





the shared pool
          這部分sga呢經常定義過大.好多dba基本不知道它用於什麼,如何確定它是否大小合理.因此他們說只要夠大就越好!有時它並不是足夠大,但經常這樣會造成浪費反而影響了效能.



chunks 大塊
           為了更好理解共享池,你至少知道或瞭解x$ksmsp.它的每條記錄代表一大塊a chunk of共享池記憶體

select ksmchcom,ksmchcls,ksmchsiz from x$ksmsp;

kgl handles           recr            496
pl/sql mpcode         recr           1924
sql area              recr           1208

       當每一個共享池大塊被分配時,程式碼把註解傳遞給實行這個分配的函式.這個註解就是對應上面的ksmchcom,用於描述所分配記憶體的用途.

       每個大塊chunk就是少量大於它包含物件的一個記憶體塊(a little larger than the object it contains),因為它是一個16 byte頭(用於識別型別,級別,大塊大小,包含用於共享池管理的鏈式列表
或連結串列的指標).

       這裡列出記憶體大塊的四種主要型別.這些資訊可以從x$ksmsp的ksmchcls看到




             free
                 這個自由或空閒的大塊不包含一個有效的物件,可以沒有限制進行分配

             recr
                 重建大塊包含一些物件,這些物件如有必要可以暫時從記憶體中移走,如有必要可再次重建。比如,與共享sql語句相關的一些大塊就是可重建的.
            
             freeabl
                  freeable大塊包含一些物件,這些物件正常情況是一個會話或呼叫所必需的,從此以後可以freed.但是有時侯可以早期或更早就freed,可以是全部
                  或部分.freeable 大塊不能從記憶體暫時被移除,因為它們不能重建.

             perm
                 permanent 記憶體大塊包含一些persist持續的物件.大型或較大的固定記憶體大塊可能包含內部空閒空間,它們會根據需要released into共享池中.


        



free lists
    共享池的自由或空閒大塊free chunks根據它們的大小,系統性分為自由列表free lists或者桶buckets.
下面為buckets編號和空閒大塊大小


free list buckets and chunks

buckets number                                  free chunk sizes
0                                               up to 79 bytes

1                                               80 bytes to 143 bytes

2                                               144 bytes to 271 bytes

3                                               272 bytes to 527 bytes


4                                               528 bytes to 1039 bytes


5                                               1040 to 2063 bytes

6                                               2064 to 4111 bytes

7                                               4112 to 8207 bytes

8                                               8208 to 16399 bytes

9                                               16400 to 32783 bytes

10                                              32784 之上


   你可能發現每個自由列表的空閒大塊大小最左端數值是一個binary power加上16 byte 頭.



   當一個程式需要一大塊共享池記憶體時,它首先掃描最適合大小的chunk的目標自由列表.如果最合適的一個大塊沒有找到,這
時掃描繼續到自由列表的尾部去查詢,查詢下一個最大可用的大塊.如果下一個最大可用的大塊為>=24 bytes(比需要的),這時
這個大塊被分割,餘下或剩下的自由或空閒空間大塊會新增到合適的自由列表中.但是如果自由列表不包含所需要大小的大塊,會從下一個
非空的自由列表中提取或分配take最小的大塊.如果所有餘下的自由列表是空的empty,然後會嘗試一個lru chain scan,這會在後面講解.

    自由列表掃描,管理,大塊分配皆是在shared pool latch保護下進行工作的.顯然,如果共享池包含大量的非常小的空閒大塊,shared
pool latch會持有相對而言較長的時間(在查詢這些特定的自由列表時).這也就是導致對於shared pool latch產生競爭的主要原因.而我們的
dba經常就是簡單增大共享池,不幸運的是,這僅僅只會延遲這個shared pool latch競爭的問題,最終會加劇這個問題.





lru lists
       如果一個程式在共享池自由列表上沒有找到合適大小的一個空閒記憶體大塊,它會嘗試從共享池中移除一些包含重建物件的大塊,為了
free一個更大的大塊.
       這兒有兩類重建大塊,一為pinned,二為不pinned.共享池中pinned的大塊概念或含義經常與dbms_shared_pool.keep混淆.keeping僅僅
用於library cache objects,這是一個dba的工作.但是當一些包含物件的大塊chunk正在使用時,所有的大塊會自動pinned.當這些大塊pinned時,
是不能freed.但是正常情況下unpinned 重建大塊可以freed.
       unpinned recreatable chunks在共享池中是以兩個列表方面進行組織的,一個是以lru次序來組織的(least recently used:最近最少使用).
這些就是transient短暫或瞬間的和週期重複性的recurrent lru lists.transient短暫的物件不可能再次需要,然後週期重複性的可能再次需要喲.
這些列表lists的組合或組成或構成composition改變非常快.只要它們unpinned,大塊會新增到mru(most recently used) ends末端,反之當它們再次
pinned時,會從列表中(mru)中移除掉.

       當一個程式為了一個新的分配,需要free共享池記憶體時,大塊也會從列表的lru末端移除.大塊可以在8個chunks上交替flushed--首先從瞬間列表,然後
從週期重複性列表.大塊可以不理會它們的大小而在lru order中進行flush.但是一些大塊不能flush.比如,包含一些library cache object的大塊,而且
這些object是透過dbms_shared_pool.keep作為標誌設定,是不能flush.相反這些大塊是從正被pinned的lru lists中移除的.

       unpinned recreatable chunks中的瞬間和週期重複性的lru lists長度,可以檢視x$kghlu,連同可以被flushed的大塊數目,以及由於pinning和unpinning
從lru lists中新增和移除的大塊數量.x$kghlu也顯示lru lists完全且不成功flushed的次數,以及最近如此請求失敗的大小(the size of the most recent such request
failure).

       lru lists和flushing rate的長度與應用的記憶體需要有很大關係,以及負荷的變化.較長或者較短的lru lists不一定有問題,發現大量flushing of dead chunks死的
大塊這是記憶體健康管理一部分.但是根據我的經驗,如果瞬間列表是週期重複性列表的3倍,很可能共享池定義過大,如果chunk flushes與其它lru操作的比率大於1/20,說明
共享池太小了.






spare free memory備用的空閒記憶體
       如果直接從自由列表或透過flushing從lru lists中請求一個巨大的記憶體失敗時,oracle仍然還有一個重要的方法.
   
       令人驚奇的是,最後這個方法不是合併連續的空閒大塊.當一些大塊freed時,可能與下面的大塊乾地合併.但是,oracle
只會在顯式執行了alter system flush shared_pool才會完全合併共享池空閒空間.因此即使共享池包含了足夠連續的空閒空間時,
記憶體請求可能會失敗.如果這個空閒記憶體變成fragmented不完整或碎片了,成為多個小型的大塊,這樣不能滿足巨大記憶體分配請求了.


       oracle為了滿足巨大記憶體分配請求的最後一個方法,就是release更多記憶體到共享池中.oracle會在例項啟動時keeps aside一半
的共享池記憶體.這個記憶體會慢慢根據記憶體壓力變化進行released.oracle這樣作為了減少或限制碎片.

       oracle備用空閒記憶體,在共享池的主要固定記憶體大塊中是看不見的concealed,以及一些固定表和其它一些真實固定的記憶體結構.
這種記憶體不位於或不在共享池的自由列表上,因而不用於立即immediate分配.但是,其資訊是包含在v$sgastat中.

       當有必要備用空閒記憶體的大塊會release到共享池中.ora-04031錯誤:不能在共享池中分配x bytes。這個錯誤會於所有備用的空閒
記憶體用完,才會觸發這個錯誤.
       如果執行峰值負荷一些時間了,仍有相當數量的備用空閒記憶體,這可能表明共享池配置過於大(大於必要).

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9240380/viewspace-662362/,如需轉載,請註明出處,否則將追究法律責任。

相關文章