亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Golang為什么占用那么多的虛擬內(nèi)存原理解析

 更新時間:2024年01月16日 11:46:45   作者:磊豐?Go語言圈  
這篇文章主要介紹了Golang為什么占用那么多的虛擬內(nèi)存原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

Go占用虛擬內(nèi)存的大小可能受到多種因素的影響,包括運行時的內(nèi)存分配、goroutine的數(shù)量、程序邏輯等。虛擬內(nèi)存的大小并不等同于實際使用的物理內(nèi)存大小,因為虛擬內(nèi)存包括未分配的內(nèi)存空間。

以下是一些可能導致Go程序占用較多虛擬內(nèi)存的原因,以及如何使用 pprof 包進行內(nèi)存分析:

以下是一些常見的原因:

  • 內(nèi)存分配問題:Go有自己的內(nèi)存分配策略,使用了一種稱為"mmap"的技術,這可能導致程序占用更多的虛擬內(nèi)存。這樣的設計能夠更好地支持并發(fā)和垃圾回收。

  • GC(垃圾回收)機制:Go的垃圾回收機制可能會導致虛擬內(nèi)存的增長。垃圾回收過程中,可能會有一些未釋放的內(nèi)存。

  • COW(寫時復制)機制:Go在進行內(nèi)存分配時,采用了寫時復制的機制,這也可能導致虛擬內(nèi)存的增長

1. 內(nèi)存分配問題

Go中的內(nèi)存分配是由運行時管理的,而不是手動控制。如果程序中存在頻繁的內(nèi)存分配和釋放,可能導致虛擬內(nèi)存的增加。

package main
import (
    "fmt"
    "time"
)
func allocateMemory() {
    for i := 0; i < 100000; i++ {
        _ = make([]byte, 1024)
    }
}
func main() {
    allocateMemory()
    fmt.Println("Memory allocated.")
    time.Sleep(time.Hour) // 保持程序運行以便分析
}

2 GC(垃圾回收)機制

垃圾回收通過標記-清除算法和并發(fā)處理來實現(xiàn)。在垃圾回收過程中,可能存在一些未釋放的內(nèi)存,但這是正常的行為,Go會在需要的時候進行垃圾回收。

package main
import (
    "fmt"
    "runtime"
    "time"
)
// Object 是一個簡單的對象結構
type Object struct {
    data []byte
}
func main() {
    // 設置每秒觸發(fā)一次垃圾回收
    go func() {
        for {
            runtime.GC()
            time.Sleep(time.Second)
        }
    }()
    // 創(chuàng)建對象并讓它們變得不可達
    for i := 0; i < 10; i++ {
        createObjects()
        time.Sleep(500 * time.Millisecond)
    }
}
func createObjects() {
    // 創(chuàng)建一些對象并讓它們變得不可達
    for i := 0; i < 10000; i++ {
        obj := createObject()
        _ = obj
    }
}
func createObject() *Object {
    // 創(chuàng)建一個對象
    obj := &Object{
        data: make([]byte, 1024),
    }
    return obj
}

3. COW(寫時復制)機制

在Go中,寫時復制(Copy-On-Write)機制通常指的是當一個值被復制時,實際上只有在需要修改其中一個副本時才進行真正的復制,這樣可以節(jié)省內(nèi)存。

在Go的切片(slice)和映射(map)中,由于它們是引用類型,采用了寫時復制的策略。下面是一個簡單的例子:

package main
import (
    "fmt"
)
func main() {
    // 創(chuàng)建一個切片
    slice1 := []int{1, 2, 3, 4, 5}
    // 創(chuàng)建另一個切片,實際上并沒有復制底層數(shù)組
    slice2 := slice1
    // 修改第一個切片,此時會觸發(fā)寫時復制
    slice1[0] = 99
    // 輸出兩個切片的值
    fmt.Println("Slice 1:", slice1) // 輸出 [99 2 3 4 5]
    fmt.Println("Slice 2:", slice2) // 輸出 [99 2 3 4 5]
}

例子中,當 slice1 修改后,Go 會檢測到 slice2 也引用了相同的底層數(shù)組,因此會觸發(fā)寫時復制,將底層數(shù)組復制一份,使得兩個切片的底層數(shù)組不再共享。

這種寫時復制的機制有助于減少內(nèi)存占用,因為只有在有修改的時候才會進行復制。然而,需要注意的是,如果在并發(fā)環(huán)境下同時修改兩個切片,可能會導致意外的結果,因為它們的底層數(shù)組不再共享。因此,在并發(fā)編程中,需要采取適當?shù)耐酱胧?/p>

4. Goroutine 數(shù)量

每個goroutine都有自己的??臻g,如果程序啟動了大量的goroutine,可能會導致虛擬內(nèi)存的增加。

package main
import (
    "fmt"
    "runtime"
    "time"
)
func createGoroutines() {
    for i := 0; i < 100000; i++ {
        go func() {
            time.Sleep(time.Hour)
        }()
    }
}
func main() {
    createGoroutines()
    fmt.Println("Goroutines created.")
    time.Sleep(time.Hour) // 保持程序運行以便分析
}

使用 `pprof` 進行內(nèi)存分析

1 導入 net/http/pprof 包并啟動一個HTTP服務器:

import (
    _ "net/http/pprof"
    "net/http"
)
func main() {
    go func() {
        http.ListenAndServe("localhost:6060", nil)
    }()
    // Your program logic here
}

2 啟動程序,并訪問 http://localhost:6060/debug/pprof/ 進行分析。

例如,你可以訪問 http://localhost:6060/debug/pprof/heap 查看堆內(nèi)存的分配情況。

go run your_program.go

3 使用 go tool pprof 進行命令行分析:

package main
import (
    "net/http"
    _ "net/http/pprof"
    "time"
)
func main() {
    go func() {
        // 啟動 pprof 服務器
        http.ListenAndServe("localhost:6060", nil)
    }()
    // 模擬一個可能導致虛擬內(nèi)存增長的操作
    for {
        allocateMemory()
        time.Sleep(1 * time.Second)
    }
}
func allocateMemory() {
    // 模擬內(nèi)存分配
    data := make([]byte, 1<<20) // 分配1MB內(nèi)存
    _ = data
}

在上述代碼中,我們在一個goroutine中啟動了pprof服務器,然后在allocateMemory函數(shù)中模擬了一個可能導致虛擬內(nèi)存增長的操作。

運行程序并進行分析

1 運行程序:

go run your-program.go

2 打開瀏覽器,訪問 http://localhost:6060/debug/pprof/,可以看到各種 pprof 的分析頁面。

3 點擊 heap 頁面,可以查看內(nèi)存使用情況。

4 如果想使用命令行工具進行分析,可以使用 go tool pprof

go tool pprof http://localhost:6060/debug/pprof/heap

然后可以使用不同的命令進行分析,比如 top、list 等。

通過分析 pprof 數(shù)據(jù),你可以更詳細地了解程序的內(nèi)存使用情況,找到可能導致虛擬內(nèi)存增長的原因。

以上就是Golang為什么占用那么多的虛擬內(nèi)存原理解析的詳細內(nèi)容,更多關于Golang虛擬內(nèi)存占用的資料請關注腳本之家其它相關文章!

相關文章

  • Go語言copy()實現(xiàn)切片復制

    Go語言copy()實現(xiàn)切片復制

    本文主要介紹了Go語言copy()實現(xiàn)切片復制,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-04-04
  • go?字符串修改的操作代碼

    go?字符串修改的操作代碼

    這篇文章主要介紹了go?字符串修改,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • Golang單元測試中的技巧分享

    Golang單元測試中的技巧分享

    這篇文章主要為大家詳細介紹了Golang進行單元測試時的一些技巧和科技,文中的示例代碼講解詳細,具有一定的參考價值,感興趣的小伙伴可以了解一下
    2023-03-03
  • Gin框架自帶參數(shù)校驗的使用詳解

    Gin框架自帶參數(shù)校驗的使用詳解

    這篇文章主要為大家詳細介紹了如何使用Gin框架自帶的參數(shù)校驗,文中的示例代碼講解詳細,具有一定的學習價值,感興趣的小伙伴可以了解下
    2023-09-09
  • Golang并發(fā)編程中Context包的使用與并發(fā)控制

    Golang并發(fā)編程中Context包的使用與并發(fā)控制

    Golang的context包提供了在并發(fā)編程中傳遞取消信號、超時控制和元數(shù)據(jù)的功能,本文就來介紹一下Golang并發(fā)編程中Context包的使用與并發(fā)控制,感興趣的可以了解一下
    2024-11-11
  • Go語言atomic.Value如何不加鎖保證數(shù)據(jù)線程安全?

    Go語言atomic.Value如何不加鎖保證數(shù)據(jù)線程安全?

    這篇文章主要介紹了Go語言atomic.Value如何不加鎖保證數(shù)據(jù)線程安全詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • Go語言中比較兩個map[string]interface{}是否相等

    Go語言中比較兩個map[string]interface{}是否相等

    本文主要介紹了Go語言中比較兩個map[string]interface{}是否相等,我們可以將其轉化成順序一樣的 slice ,然后再轉化未json,具有一定的參考價值,感興趣的可以了解一下
    2023-08-08
  • 使用Go實現(xiàn)健壯的內(nèi)存型緩存的方法

    使用Go實現(xiàn)健壯的內(nèi)存型緩存的方法

    這篇文章主要介紹了使用Go實現(xiàn)健壯的內(nèi)存型緩存,本文比較了字節(jié)緩存和結構體緩存的優(yōu)劣勢,介紹了緩存穿透、緩存錯誤、緩存預熱、緩存?zhèn)鬏敗⒐收限D移、緩存淘汰等問題,并對一些常見的緩存庫進行了基準測試,需要的朋友可以參考下
    2022-05-05
  • Golang實現(xiàn)加權輪詢負載均衡算法

    Golang實現(xiàn)加權輪詢負載均衡算法

    加權輪詢負載均衡算法是一種常見的負載均衡策略,本文主要介紹了Golang實現(xiàn)加權輪詢負載均衡算法,具有一定的參考價值,感興趣的可以了解一下
    2024-08-08
  • Go語言實現(xiàn)Viper配置管理筆記

    Go語言實現(xiàn)Viper配置管理筆記

    Viper 是一個功能強大、靈活易用的配置管理工具,本文主要介紹了Go語言實現(xiàn)Viper配置管理筆記,具有一定的參考價值,感興趣的可以了解一下
    2025-04-04

最新評論