爲什麼 Go 佔用那麼多的虛擬內存?

什麼是虛擬內存

虛擬內存(Virtual Memory)是計算機系統中的一種技術,它允許程序使用比實際物理內存更大的內存空間。虛擬內存的概念和實現是爲了解決以下問題:

內存限制:計算機系統的物理內存是有限的,而運行的程序可能需要比物理內存更多的內存空間。虛擬內存提供了一個抽象的、更大的內存空間供程序使用。

內存隔離:虛擬內存可以將不同的程序或進程隔離開,使它們擁有各自獨立的內存空間,互不干擾。這樣可以提高系統的穩定性和安全性。

虛擬內存通過將物理內存和磁盤空間結合起來來實現這些功能。它使用了一種稱爲頁面(Page)的固定大小的內存塊作爲內存管理的基本單位。物理內存被分成相同大小的頁面,而虛擬內存空間也被分成相同大小的頁面。

當程序訪問虛擬內存時,操作系統將虛擬地址轉換爲物理地址。如果所需的頁面當前不在物理內存中,操作系統會將頁面從磁盤讀取到物理內存中,然後將虛擬地址映射到該物理地址上。這個過程稱爲頁面調度(Page Swapping)或頁面置換(Page Replacement)。

虛擬內存的優點包括:

更大的內存空間:虛擬內存使得程序能夠使用比物理內存更大的內存空間,從而支持運行更大規模的應用程序。

內存隔離:不同的程序之間相互隔離,互不干擾。一個程序的錯誤或異常不會直接影響其他程序的執行。

簡化內存管理:虛擬內存使得內存管理更加方便,程序員不需要關心實際的物理內存情況,可以專注於邏輯設計和開發。

虛擬內存的實現需要硬件和操作系統的支持,包括內存管理單元(MMU)和相關的地址映射機制。

在許多現代計算機系統中,虛擬內存是操作系統的一個核心功能,並廣泛用於各種應用程序的執行和管理。

爲什麼 Go 佔用那麼多的虛擬內存?

Go 在使用虛擬內存方面可能會表現出較高的佔用量,這是由於 Go 運行時的內存管理策略所導致的。Go 運行時使用了一種稱爲 "分段堆棧"(segmented stack)的技術來管理 Goroutine 的堆棧,這種技術可以提供更高的併發性能和更小的堆棧內存消耗,但會導致虛擬內存佔用的增加。

以下是一段簡單的 Go 代碼,用於說明虛擬內存佔用的情況:

package main

import (
    "fmt"
    "time"
)

func worker() {
    for {
        time.Sleep(time.Second)
    }
}

func main() {
    go worker()

    var input string
    fmt.Scanln(&input)
    fmt.Println("Program exited")
}

上述代碼創建了一個簡單的 Goroutine,該 Goroutine 持續地睡眠 1 秒鐘。主函數等待用戶輸入後打印一條消息。這個程序在沒有用戶輸入時會一直運行下去。

當運行該程序時,您可能會注意到它的虛擬內存佔用量相對較高。這是因爲 Go 運行時默認會爲每個 Goroutine 分配一塊較大的虛擬內存空間,以便在需要時可以自動擴展堆棧的大小。這種機制確保了 Goroutine 的可伸縮性和高併發性能,但也會導致虛擬內存佔用的增加。

由於 Go 運行時的內存管理策略,虛擬內存佔用的增加並不會直接轉化爲實際物理內存的消耗。

操作系統會根據需要動態地將虛擬內存映射到物理內存中,因此實際的內存佔用可能相對較低。

如果您對虛擬內存佔用量感到擔憂,可以通過設置 GODEBUG 環境變量的 gctrace 標誌來觀察 Go 運行時的垃圾回收行爲和內存分配情況。例如,GODEBUG=gctrace=1 可以輸出垃圾回收的調試信息。

需要注意的是,虛擬內存佔用的具體數值和表現可能因操作系統、Go 版本和編譯參數等因素而有所差異。

因此,確切的數值可能會因環境而異。以上說明提供了一般情況下的解釋和示例。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/uXMtPtDKgzNlpmvjttTtsA