模組 Stdlib.Gc

module Gc: Gc

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.full_major (或 Gc.compact) 然後計算垃圾回收統計資料通常更簡單且更可預測,因為此時「存活」字具有「程式可存取」的簡單含義。一個注意事項是,單次呼叫 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; (*

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

*)
   verbose : int; (*

此值會控制標準錯誤輸出上的垃圾回收訊息。它是下列某些旗標的總和,可在對應的事件上列印訊息

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

當估計的「浪費」記憶體量超過存活資料量的 max_overhead 百分比時,會觸發堆積壓縮。如果 max_overhead 設定為 0,則在每個主要垃圾回收週期的結束時會觸發堆積壓縮(此設定僅用於測試目的)。如果 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; (*

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

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

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

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

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

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

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

  • 自從 4.08
*)
}

垃圾回收參數會以 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 必須是堆積配置的。f 會在 v 第一次變成無法存取(包括透過弱指標)與 GC 收集 v 之間,以 v 作為引數被呼叫。可以為相同的值註冊多個函式,甚至是同一個函式的多個執行個體。每個執行個體都會被呼叫一次(如果程式在 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 的所有功能,包括使值再次變成可存取的指派。它也可以永遠迴圈(在這種情況下,其他最終化函式不會在 f 的執行期間被呼叫,除非它呼叫 finalise_release)。它可以針對 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,則適用於在頂層使用

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 是一個剖析引擎,會隨機取樣配置的記憶體字詞。