模組 Gc

module Gc: sig .. end

記憶體管理控制與統計;已完成的值。


type stat = {
   minor_words : float; (*

程式啟動以來在次要堆積中配置的字組數量。

*)
   promoted_words : float; (*

程式啟動以來在次要堆積中配置,並在次要回收後移動到主要堆積的字組數量。

*)
   major_words : float; (*

程式啟動以來在主要堆積中配置的字組數量,包含提升的字組。

*)
   minor_collections : int; (*

程式啟動以來次要回收的次數。

*)
   major_collections : int; (*

程式啟動以來完成的主要回收週期次數。

*)
   heap_words : int; (*

主要堆積的總大小,以字組為單位。

*)
   heap_chunks : int; (*

組成主要堆積的連續記憶體區塊數量。此指標目前在 OCaml 5 中不可用:欄位值永遠為 0

*)
   live_words : int; (*

主要堆積中存活資料的字組數量,包含標頭字組。

請注意,「存活」字組指的是主要堆積中目前已知為不可回收的所有字組,其中包含在前一個 gc 週期開始後程式已無法存取到的字組。呼叫 Gc.full_major(或 Gc.compact)然後計算 gc 統計資料通常更簡單且更可預測,因為那時「存活」字組具有「程式可存取」的簡單含義。一個注意事項是,單次呼叫 Gc.full_major 不會回收來自 Gc.finalise 的終結器值(這不適用於 Gc.finalise_last)。如果此注意事項很重要,只需呼叫 Gc.full_major 兩次而不是一次。

*)
   live_blocks : int; (*

主要堆積中存活區塊的數量。

請參閱關於「存活」含義的注意事項:live_words

*)
   free_words : int; (*

可用列表中的字組數量。

*)
   free_blocks : int; (*

可用列表中的區塊數量。此指標目前在 OCaml 5 中不可用:欄位值永遠為 0

*)
   largest_free : int; (*

可用列表中最大區塊的大小(以字組為單位)。此指標目前在 OCaml 5 中不可用:欄位值永遠為 0

*)
   fragments : int; (*

由於碎片化而浪費的字組數量。這些是位於兩個存活區塊之間的 1 字組可用區塊。它們無法用於配置。

*)
   compactions : int; (*

程式啟動以來堆積壓縮的次數。

*)
   top_heap_words : int; (*

主要堆積達到的最大大小,以字組為單位。

*)
   stack_size : int; (*

堆疊目前的佔用大小,以字組為單位。此指標目前在 OCaml 5 中不可用:欄位值永遠為 0

  • 自從 3.12
*)
   forced_major_collections : int; (*

程式啟動以來完成的強制完整主要回收次數。

  • 自從 4.12
*)
}

記憶體管理計數器會以 stat 記錄傳回。這些計數器會提供整個程式的值。

程式啟動以來配置的總記憶體量(以字組為單位)為 minor_words + major_words - promoted_words。乘以字組大小(32 位元機器為 4,64 位元機器為 8)即可取得位元組數。

type control = {
   minor_heap_size : int; (*

次要堆積的大小(以字組為單位)。變更此參數會觸發次要回收。此程式使用的次要堆積總大小是作用中網域堆積大小的總和。預設值:256k。

*)
   major_heap_increment : int; (*

增加主要堆積時要新增的量。如果此數字小於或等於 1000,則它是目前堆積大小的百分比(即設定為 100 會使堆積大小在每次增加時加倍)。如果大於 1000,則它是將新增到堆積的固定字組數。預設值:15。

*)
   space_overhead : int; (*

主要 GC 速度是根據此參數計算。這是將「浪費」的記憶體,因為 GC 不會立即回收無法存取的區塊。它表示為存活資料使用記憶體的百分比。如果 space_overhead 較小,GC 會執行更多工作(使用更多 CPU 時間並更積極地回收區塊)。預設值:120。

*)
   verbose : int; (*

此值控制標準錯誤輸出上的 GC 訊息。它是下列一些旗標的總和,用來列印對應事件的訊息

  • 0x001 主要 GC 週期的開始和結束。
  • 0x002 次要回收和主要 GC 片段。
  • 0x004 堆積的擴大和縮小。
  • 0x008 堆疊和記憶體管理員表格的大小調整。
  • 0x010 堆積壓縮。
  • 0x020 GC 參數的變更。
  • 0x040 主要 GC 片段大小的計算。
  • 0x080 終結函式的呼叫。
  • 0x100 啟動時的位元組碼可執行檔和共用程式庫搜尋。
  • 0x200 壓縮觸發條件的計算。
  • 0x400 在程式結束時輸出 GC 統計資料。預設值:0。
*)
   max_overhead : int; (*

當預估的「浪費」記憶體量超過存活資料量的 max_overhead 百分比時,就會觸發堆積壓縮。如果 max_overhead 設定為 0,則會在每個主要 GC 週期結束時觸發堆積壓縮(此設定僅適用於測試目的)。如果 max_overhead >= 1000000,則永遠不會觸發壓縮。預設值:500。

*)
   stack_limit : int; (*

纖程堆疊的最大大小(以字組為單位)。預設值:1024k。

*)
   allocation_policy : int; (*

主要堆積中用於配置的原則。

此選項在 OCaml 5.x 中會被忽略。

在 OCaml 5.0 之前,可能的值為 0、1 和 2。

  • 0 是 next-fit 原則
  • 1 是 first-fit 原則(自 OCaml 3.11 起)
  • 2 是 best-fit 原則(自 OCaml 4.10 起)
  • 自從 3.11
*)
   window_size : int; (*

主要 GC 用於平滑工作負載變化的視窗大小。這是一個介於 1 和 50 之間的整數。預設值:1。

  • 自從 4.03
*)
   custom_major_ratio : int; (*

主要堆積中自訂值所持有的堆積外浮動垃圾與主要堆積大小的目標比例。調整 GC 速度以嘗試將此記憶體量用於尚未回收的無效值。表示為主要堆積大小的百分比。預設值會讓堆積外浮動垃圾與堆積內額外負荷的大小大致相同。注意:這僅適用於使用 caml_alloc_custom_mem 配置的值(例如 bigarrays)。預設值:44。

  • 自從 4.08
*)
   custom_minor_ratio : int; (*

次要堆積中自訂值所持有的堆積外記憶體的浮動垃圾限制。當次要堆積中自訂值持有這麼多記憶體時,會觸發次要 GC。表示為次要堆積大小的百分比。注意:這僅適用於使用 caml_alloc_custom_mem 配置的值(例如 bigarrays)。預設值:100。

  • 自從 4.08
*)
   custom_minor_max_size : int; (*

配置在次要堆積中的每個自訂值的最大堆積外記憶體量。持有超過這麼多位元組的自訂值會配置在主要堆積中。注意:這僅適用於使用 caml_alloc_custom_mem 配置的值(例如 bigarrays)。預設值:70000 位元組。

  • 自從 4.08
*)
}

GC 參數以 control 記錄給定。請注意,這些參數也可以透過設定 OCAMLRUNPARAM 環境變數來初始化。請參閱 ocamlrun 的文件。

val stat : unit -> stat

傳回 stat 記錄中記憶體管理計數器的目前值,這些值代表程式的總記憶體統計資料。此函式會造成完整的主要回收。

val quick_stat : unit -> stat

stat 相同,但 live_wordslive_blocksfree_wordsfree_blockslargest_freefragments 設定為 0。由於每個網域的緩衝區,它可能僅代表自上次次要回收或主要週期以來程式總記憶體使用量的狀態。此函式比 stat 快得多,因為它不需要觸發完整的主要回收。

val counters : unit -> float * float * float

傳回目前網域或可能先前網域的 (minor_words, promoted_words, major_words)。此函式與 quick_stat 一樣快。

val minor_words : unit -> float

此網域或可能先前網域在次要堆積中配置的字組數量。此數字在位元組碼程式中是準確的,但在編譯為原生碼的程式中僅為近似值。

在原生碼中,此函式不會配置。

val get : unit -> control

傳回 control 記錄中 GC 參數的目前值。

val set : control -> unit

set r 根據 control 記錄 r 變更 GC 參數。正常用法為:Gc.set { (Gc.get()) with Gc.verbose = 0x00d }

val minor : unit -> unit

觸發次要回收。

val major_slice : int -> int

major_slice n 執行次要回收和主要回收的片段。n 是片段的大小:GC 會執行足夠的工作以釋放(平均)n 個字組的記憶體。如果 n = 0,則 GC 會嘗試執行足夠的工作以確保下一個自動片段沒有工作要做。此函式會傳回未指定的整數(目前:0)。

val major : unit -> unit

執行次要回收並完成目前的主要回收週期。

val full_major : unit -> unit

執行次要回收、完成目前的主要回收週期,並執行全新的完整週期。這會回收所有目前無法存取的區塊。

val compact : unit -> unit

執行完整的主要回收並壓縮堆積。請注意,堆積壓縮是一項冗長的操作。

val print_stat : out_channel -> unit

將程式整體記憶體管理計數器(以人類可讀的形式)的當前值列印到通道參數中。

val allocated_bytes : unit -> float

傳回此域以及可能先前域所分配的位元組數。它以 float 傳回,以避免在 32 位元機器上使用 int 時發生溢位問題。

val get_minor_free : unit -> int

傳回此域次要堆積中可用空間的當前大小。

val finalise : ('a -> unit) -> 'a -> unit

finalise f vf 註冊為 v 的終結函數。v 必須是堆積配置的。在 v 第一次變得無法存取(包括通過弱指標)和 GC 收集 v 之間的時間點,將會以 v 作為引數呼叫 f。可以為同一個值註冊多個函數,甚至是同一個函數的多個實例。每個實例都將被呼叫一次(或者如果程式在 v 變得無法存取之前終止,則永遠不會被呼叫)。

GC 將按照釋放的順序呼叫終結函數。當多個值同時變得無法存取時(即在同一個 GC 週期內),將按照對應呼叫 finalise 的相反順序呼叫終結函數。如果 finalise 的呼叫順序與值的配置順序相同,則表示每個值都會在其所依賴的值之前終結。當然,如果透過賦值引入額外的依賴關係,則此情況為假。

在存在多個 OCaml 執行緒的情況下,應假設任何特定的終結器都可能在任何執行緒中執行。

從終結函數的閉包中可存取的任何內容都被視為可存取,因此以下程式碼將無法如預期般運作

  •  let v = ... in Gc.finalise (fun _ -> ...v...) v 

相反地,您應該確保 v 不在終結函數的閉包中,方法是編寫

  •  let f = fun x -> ...  let v = ... in Gc.finalise f v 

f 函數可以使用 OCaml 的所有功能,包括使值再次可存取的賦值。它也可以永遠迴圈(在這種情況下,除非它呼叫 finalise_release,否則在 f 執行期間不會呼叫其他終結函數)。它可以對 v 或其他值呼叫 finalise,以註冊其他函數,甚至是它本身。它可以引發例外狀況;在這種情況下,例外狀況將會中斷函數被呼叫時程式正在執行的任何操作。

如果無法保證 v 是堆積配置的,則 finalise 將會引發 Invalid_argument。一些不是堆積配置的值的例子包括整數、常數建構函式、布林值、空陣列、空列表、單位值。確切的堆積配置與否的列表取決於實作。某些常數值可以在程式的生命週期中堆積配置但永遠不會釋放,例如整數常數列表;這也取決於實作。請注意,float 類型的值有時會配置,有時不會配置,因此終結它們是不安全的,並且 finalise 也會為它們引發 Invalid_argument。類型為 'Lazy.t(對於任何 'a)的值在這方面與 float 類似,但編譯器有時會以防止 finalise 偵測到它們的方式來最佳化它們。在這種情況下,它不會引發 Invalid_argument,但您仍應避免對惰性值呼叫 finalise

保證呼叫 String.makeBytes.makeBytes.createArray.makeref 的結果是堆積配置的且非常數的,除非長度引數為 0

val finalise_last : (unit -> unit) -> 'a -> unit

Gc.finalise 相同,只是沒有將值作為引數給定。因此,您不能使用給定的值來計算終結函數。好處是該函數是在值最後一次無法存取後而不是第一次無法存取後被呼叫的。因此,與 Gc.finalise 相反,該值將永遠不會再次可存取或再次使用。特別是,包含此值作為鍵或資料的每個弱指標和暫存器在執行終結函數之前都會被取消設定。此外,使用 Gc.finalise 附加的終結函數始終在 使用 Gc.finalise_last 附加的終結函數之前被呼叫。

val finalise_release : unit -> unit

終結函數可以呼叫 finalise_release 來告知 GC 它可以啟動下一個終結函數,而無需等待目前的終結函數傳回。

type alarm 

警報是一種資料,它會在主要 GC 週期結束時呼叫使用者函數。提供以下函數來建立和刪除警報。

val create_alarm : (unit -> unit) -> alarm

create_alarm f 將安排在主要 GC 週期結束時呼叫 f,而不是由 f 本身引起的,從目前的週期或下一個週期開始。f 將在建立警報的相同域上執行,直到域退出或呼叫 delete_alarm。會傳回類型為 alarm 的值,您可以使用它來呼叫 delete_alarm

不保證 Gc 警報會在每個主要 GC 週期結束時執行,但保證它最終會執行。

例如,這裡有一個粗略的方法來中斷一個函數,如果程式的記憶體消耗超過指定的 MB limit,適用於在 toplevel 中使用

let run_with_memory_limit (limit : int) (f : unit -> 'a) : 'a =
  let limit_memory () =
    let mem = Gc.(quick_stat ()).heap_words in
    if mem / (1024 * 1024) > limit / (Sys.word_size / 8) then
      raise Out_of_memory
  in
  let alarm = Gc.create_alarm limit_memory in
  Fun.protect f ~finally:(fun () -> Gc.delete_alarm alarm ; Gc.compact ())
   
val delete_alarm : alarm -> unit

delete_alarm a 將停止對與 a 關聯的函數的呼叫。再次呼叫 delete_alarm a 沒有任何作用。

val eventlog_pause : unit -> unit
已棄用。請改用 Runtime_events.pause。
val eventlog_resume : unit -> unit
已棄用。請改用 Runtime_events.resume。
module Memprof: sig .. end

Memprof 是一個剖析引擎,它會隨機取樣配置的記憶體字。