精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

為什么 Go 占用那么多的虛擬內存?

云計算 虛擬化
前段時間,某同學說某服務的容器因為超出內存限制,不斷地重啟,問我們是不是有內存泄露,趕緊排查,然后解決掉,省的出問題。

 [[349727]]

本文轉載自微信公眾號「腦子進煎魚了」,作者陳煎魚。轉載本文請聯系腦子進煎魚了公眾號。 

前段時間,某同學說某服務的容器因為超出內存限制,不斷地重啟,問我們是不是有內存泄露,趕緊排查,然后解決掉,省的出問題。

我們大為震驚,趕緊查看監控+報警系統和性能分析,發現應用指標壓根就不高,不像有泄露的樣子。

問題到底是出在哪里了呢,我們進入某個容器里查看了 top 的系統指標:

  1. PID       VSZ    RSS   ... COMMAND 
  2. 67459     2007m  136m  ... ./eddycjy-server 

看上去也沒什么大開銷的東西,就一個 Go 進程?就這?

再定眼一看,某同學就說 VSZ 那么高,而某云上的容器內存指標居然恰好和 VSZ 的值相接近,因此就懷疑是不是 VSZ 所導致的,覺得存在一定的關聯關系。

這個猜測的結果到底是否正確呢?

基礎知識

本篇文章將主要圍繞 Go 進程的 VSZ 來進行剖析,看看到底它為什么那么 "高"。

第一節為前置的補充知識,大家可按順序閱讀。

什么是 VSZ

VSZ 是該進程所能使用的虛擬內存總大小,它包括進程可以訪問的所有內存,其中包括了被換出的內存(Swap)、已分配但未使用的內存以及來自共享庫的內存。

為什么要虛擬內存

在前面我們有了解到 VSZ 其實就是該進程的虛擬內存總大小,那如果我們想了解 VSZ 的話,那我們得先了解 “為什么要虛擬內存?”。

本質上來講,在一個系統中的進程是與其他進程共享 CPU 和主存資源的。

因此在現代的操作系統中,多進程的使用非常的常見,如果太多的進程需要太多的內存,在沒有虛擬內存的情況下,物理內存很可能會不夠用,就會導致其中有些任務無法運行,更甚至會出現一些很奇怪的現象。

例如 “某一個進程不小心寫了另一個進程使用的內存”,就會造成內存破壞,因此虛擬內存是非常重要的一個媒介。

虛擬內存包含了什么

虛擬內存,又分為:

  • 內核虛擬內存。
  • 進程虛擬內存。

每一個進程的虛擬內存都是獨立的, 內部結構如下圖所示。

在內核虛擬內存中,包含了內核中的代碼和數據結構。

內核虛擬內存中的某些區域會被映射到所有進程共享的物理頁面中去,因此你會看到 ”內核虛擬內存“ 中實際上是包含了 ”物理內存“ 的,它們兩者存在映射關系。

而從應用場景上來講,每個進程也會去共享內核的代碼和全局數據結構,因此就會被映射到所有進程的物理頁面中去。

虛擬內存的重要能力

為了更有效地管理內存并且減少出錯,現代系統提供了一種對主存的抽象概念,也就是今天的主角,叫做虛擬內存(VM)。

虛擬內存是硬件異常、硬件地址翻譯、主存、磁盤文件和內核軟件交互的地方,它為每個進程提供了一個大的、一致的和私有的地址空間,虛擬內存提供了三個重要的能力:

它將主存看成是一個存儲在磁盤上的地址空間的高速緩存,在主存中只保存活動區域,并根據需要在磁盤和主存之間來回傳送數據,通過這種方式,它高效地使用了主存。

它為每個進程提供了一致的地址空間,從而簡化了內存管理。

它保護了每個進程的地址空間不被其他進程破壞。

小結

上面發散的可能比較多,簡單來講,對于本文我們重點關注這些知識點,如下:

  • 虛擬內存它是有各式各樣內存交互的地方,它包含的不僅僅是 "自己",而在本文中,我們只需要關注 VSZ,也就是進程虛擬內存,它包含了你的代碼、數據、堆、棧段和共享庫。
  • 虛擬內存作為內存保護的工具,能夠保證進程之間的內存空間獨立,不受其他進程的影響,因此每一個進程的 VSZ 大小都不一樣,互不影響。
  • 虛擬內存的存在,系統給各進程分配的內存之和是可以大于實際可用的物理內存的,因此你也會發現你進程的物理內存總是比虛擬內存低的多的多。

排查問題

在了解了基礎知識后,我們正式開始排查問題,第一步我們先編寫一個測試程序,看看沒有什么業務邏輯的 Go 程序,它初始的 VSZ 是怎么樣的。

測試

應用代碼:

  1. func main() { 
  2.  r := gin.Default() 
  3.  r.GET("/ping", func(c *gin.Context) { 
  4.   c.JSON(200, gin.H{ 
  5.    "message""pong"
  6.   }) 
  7.  }) 
  8.  r.Run(":8001"

查看進程情況:

  1. $ ps aux 67459 
  2. USER      PID  %CPU %MEM      VSZ    RSS   ... 
  3. eddycjy 67459   0.0  0.0  4297048    960   ... 

從結果上來看,VSZ 為 4297048K,也就是 4G 左右,咋一眼看過去還是挺嚇人的,明明沒有什么業務邏輯,但是為什么那么高呢,真是令人感到好奇。

確認有沒有泄露

在未知的情況下,我們可以首先看下 runtime.MemStats 和 pprof,確定應用到底有沒有泄露。不過我們這塊是演示程序,什么業務邏輯都沒有,因此可以確定和應用沒有直接關系。

  1. # runtime.MemStats 
  2. # Alloc = 1298568 
  3. # TotalAlloc = 1298568 
  4. # Sys = 71893240 
  5. # Lookups = 0 
  6. # Mallocs = 10013 
  7. # Frees = 834 
  8. # HeapAlloc = 1298568 
  9. # HeapSys = 66551808 
  10. # HeapIdle = 64012288 
  11. # HeapInuse = 2539520 
  12. # HeapReleased = 64012288 
  13. # HeapObjects = 9179 
  14. ... 

Go FAQ

接著我第一反應是去翻了 Go FAQ(因為看到過,有印象),其問題為 "Why does my Go process use so much virtual memory?",回答如下:

The Go memory allocator reserves a large region of virtual memory as an arena for allocations. This virtual memory is local to the specific Go process; the reservation does not deprive other processes of memory.

To find the amount of actual memory allocated to a Go process, use the Unix top command and consult the RES (Linux) or RSIZE (macOS) columns.

這個 FAQ 是在 2012 年 10 月 提交 的,這么多年了也沒有更進一步的說明,再翻了 issues 和 forum,一些關閉掉的 issue 都指向了 FAQ,這顯然無法滿足我的求知欲,因此我繼續往下探索,看看里面到底都擺了些什么。

查看內存映射

在上圖中,我們有提到進程虛擬內存,主要包含了你的代碼、數據、堆、棧段和共享庫,那初步懷疑是不是進程做了什么內存映射,導致了大量的內存空間被保留呢,為了確定這一點,我們通過如下命令去排查:

  1. $ vmmap --wide 67459 
  2. ... 
  3. ==== Non-writable regions for process 67459 
  4. REGION TYPE                      START - END             [ VSIZE  RSDNT  DIRTY   SWAP] PRT/MAX SHRMOD PURGE    REGION DETAIL 
  5. __TEXT                 00000001065ff000-000000010667b000 [  496K   492K     0K     0K] r-x/rwx SM=COW          /bin/zsh 
  6. __LINKEDIT             0000000106687000-0000000106699000 [   72K    44K     0K     0K] r--/rwx SM=COW          /bin/zsh 
  7. MALLOC metadata        000000010669b000-000000010669c000 [    4K     4K     4K     0K] r--/rwx SM=COW          DefaultMallocZone_0x10669b000 zone structure 
  8. ... 
  9. __TEXT                 00007fff76c31000-00007fff76c5f000 [  184K   168K     0K     0K] r-x/r-x SM=COW          /usr/lib/system/libxpc.dylib 
  10. __LINKEDIT             00007fffe7232000-00007ffff32cb000 [192.6M  17.4M     0K     0K] r--/r-- SM=COW          dyld shared cache combined __LINKEDIT 
  11. ...         
  12.  
  13. ==== Writable regions for process 67459 
  14. REGION TYPE                      START - END             [ VSIZE  RSDNT  DIRTY   SWAP] PRT/MAX SHRMOD PURGE    REGION DETAIL 
  15. __DATA                 000000010667b000-0000000106682000 [   28K    28K    28K     0K] rw-/rwx SM=COW          /bin/zsh 
  16. ...    
  17. __DATA                 0000000106716000-000000010671e000 [   32K    28K    28K     4K] rw-/rwx SM=COW          /usr/lib/zsh/5.3/zsh/zle.so 
  18. __DATA                 000000010671e000-000000010671f000 [    4K     4K     4K     0K] rw-/rwx SM=COW          /usr/lib/zsh/5.3/zsh/zle.so 
  19. __DATA                 0000000106745000-0000000106747000 [    8K     8K     8K     0K] rw-/rwx SM=COW          /usr/lib/zsh/5.3/zsh/complete.so 
  20. __DATA                 000000010675a000-000000010675b000 [    4K     4K     4K     0K] rw- 
  21. ... 

這塊主要是利用 macOS 的 vmmap 命令去查看內存映射情況,這樣就可以知道這個進程的內存映射情況,從輸出分析來看,這些關聯共享庫占用的空間并不大,導致 VSZ 過高的根本原因不在共享庫和二進制文件上,但是并沒有發現大量保留內存空間的行為,這是一個問題點。

注:若是 Linux 系統,可使用 cat /proc/PID/maps 或 cat /proc/PID/smaps 查看。

查看系統調用

既然在內存映射中,我們沒有明確的看到保留內存空間的行為,那我們接下來看看該進程的系統調用,確定一下它是否存在內存操作的行為,如下:

  1. $ sudo dtruss -a ./awesomeProject 
  2. ... 
  3.  4374/0x206a2:     15620       6      3 mprotect(0x1BC4000, 0x1000, 0x0)   = 0 0 
  4. ... 
  5.  4374/0x206a2:     15781       9      4 sysctl([CTL_HW, 3, 0, 0, 0, 0] (2), 0x7FFEEFBFFA64, 0x7FFEEFBFFA68, 0x0, 0x0)   = 0 0 
  6.  4374/0x206a2:     15783       3      1 sysctl([CTL_HW, 7, 0, 0, 0, 0] (2), 0x7FFEEFBFFA64, 0x7FFEEFBFFA68, 0x0, 0x0)   = 0 0 
  7.  4374/0x206a2:     15899       7      2 mmap(0x0, 0x40000, 0x3, 0x1002, 0xFFFFFFFFFFFFFFFF, 0x0)   = 0x4000000 0 
  8.  4374/0x206a2:     15930       3      1 mmap(0xC000000000, 0x4000000, 0x0, 0x1002, 0xFFFFFFFFFFFFFFFF, 0x0)   = 0xC000000000 0 
  9.  4374/0x206a2:     15934       4      2 mmap(0xC000000000, 0x4000000, 0x3, 0x1012, 0xFFFFFFFFFFFFFFFF, 0x0)   = 0xC000000000 0 
  10.  4374/0x206a2:     15936       2      0 mmap(0x0, 0x2000000, 0x3, 0x1002, 0xFFFFFFFFFFFFFFFF, 0x0)   = 0x59B7000 0 
  11.  4374/0x206a2:     15942       2      0 mmap(0x0, 0x210800, 0x3, 0x1002, 0xFFFFFFFFFFFFFFFF, 0x0)   = 0x4040000 0 
  12.  4374/0x206a2:     15947       2      0 mmap(0x0, 0x10000, 0x3, 0x1002, 0xFFFFFFFFFFFFFFFF, 0x0)   = 0x1BD0000 0 
  13.  4374/0x206a2:     15993       3      0 madvise(0xC000000000, 0x2000, 0x8)   = 0 0 
  14.  4374/0x206a2:     16004       2      0 mmap(0x0, 0x10000, 0x3, 0x1002, 0xFFFFFFFFFFFFFFFF, 0x0)   = 0x1BE0000 0 
  15. ... 

在這小節中,我們通過 macOS 的 dtruss 命令監聽并查看了運行這個程序所進行的所有系統調用,發現了與內存管理有一定關系的方法如下:

  • mmap:創建一個新的虛擬內存區域,但這里需要注意,就是當系統調用 mmap 時,它只是從虛擬內存中申請了一段空間出來,并不會去分配和映射真實的物理內存,而當你訪問這段空間的時候,才會在當前時間真正的去分配物理內存。那么對應到我們實際應用的進程中,那就是 VSZ 的增長后,而該內存空間又未正式使用的話,物理內存是不會有增長的。
  • madvise:提供有關使用內存的建議,例如:MADV_NORMAL、MADV_RANDOM、MADV_SEQUENTIAL、MADV_WILLNEED、MADV_DONTNEED 等等。
  • mprotect:設置內存區域的保護情況,例如:PROT_NONE、PROT_READ、PROT_WRITE、PROT_EXEC、PROT_SEM、PROT_SAO、PROT_GROWSUP、PROT_GROWSDOWN 等等。
  • sysctl:在內核運行時動態地修改內核的運行參數。

在此比較可疑的是 mmap 方法,它在 dtruss 的最終統計中一共調用了 10 余次,我們可以相信它在 Go Runtime 的時候進行了大量的虛擬內存申請。

我們再接著往下看,看看到底是在什么階段進行了虛擬內存空間的申請。

注:若是 Linux 系統,可使用 strace 命令。

查看 Go Runtime

啟動流程

通過上述的分析,我們可以知道在 Go 程序啟動的時候 VSZ 就已經不低了,并且確定不是共享庫等的原因,且程序在啟動時系統調用確實存在 mmap 等方法的調用。

那么我們可以充分懷疑 Go 在初始化階段就保留了該內存空間。那我們第一步要做的就是查看一下 Go 的引導啟動流程,看看是在哪里申請的。

引導過程如下:

  1. graph TD 
  2. A(rt0_darwin_amd64.s:8<br/>_rt0_amd64_darwin) -->|JMP| B(asm_amd64.s:15<br/>_rt0_amd64) 
  3. --> |JMP|C(asm_amd64.s:87<br/>runtime-rt0_go) 
  4. --> D(runtime1.go:60<br/>runtime-args) 
  5. --> E(os_darwin.go:50<br/>runtime-osinit) 
  6. --> F(proc.go:472<br/>runtime-schedinit) 
  7. --> G(proc.go:3236<br/>runtime-newproc) 
  8. --> H(proc.go:1170<br/>runtime-mstart) 
  9. --> I(在新創建的 p 和 m 上運行 runtime-main) 
  • runtime-osinit:獲取 CPU 核心數。
  • runtime-schedinit:初始化程序運行環境(包括棧、內存分配器、垃圾回收、P等)。
  • runtime-newproc:創建一個新的 G 和 綁定 runtime.main。
  • runtime-mstart:啟動線程 M。

注:來自@曹大的 《Go 程序的啟動流程》和@全成的 《Go 程序是怎樣跑起來的》,推薦大家閱讀。

初始化運行環境

顯然,我們要研究的是 runtime 里的 schedinit 方法,如下:

  1. func schedinit() { 
  2.  ... 
  3.  stackinit() 
  4.  mallocinit() 
  5.  mcommoninit(_g_.m) 
  6.  cpuinit()       // must run before alginit 
  7.  alginit()       // maps must not be used before this call 
  8.  modulesinit()   // provides activeModules 
  9.  typelinksinit() // uses maps, activeModules 
  10.  itabsinit()     // uses activeModules 
  11.  
  12.  msigsave(_g_.m) 
  13.  initSigmask = _g_.m.sigmask 
  14.  
  15.  goargs() 
  16.  goenvs() 
  17.  parsedebugvars() 
  18.  gcinit() 
  19.   ... 

從用途來看,非常明顯, mallocinit 方法會進行內存分配器的初始化,我們繼續往下看。

初始化內存分配器

mallocinit

接下來我們正式的分析一下 mallocinit 方法,在引導流程中, mallocinit 主要承擔 Go 程序的內存分配器的初始化動作,而今天主要是針對虛擬內存地址這塊進行拆解,如下:

  1. func mallocinit() { 
  2.  ... 
  3.  if sys.PtrSize == 8 { 
  4.   for i := 0x7f; i >= 0; i-- { 
  5.    var p uintptr 
  6.    switch { 
  7.    case GOARCH == "arm64" && GOOS == "darwin"
  8.     p = uintptr(i)<<40 | uintptrMask&(0x0013<<28) 
  9.    case GOARCH == "arm64"
  10.     p = uintptr(i)<<40 | uintptrMask&(0x0040<<32) 
  11.    case GOOS == "aix"
  12.     if i == 0 { 
  13.      continue 
  14.     } 
  15.     p = uintptr(i)<<40 | uintptrMask&(0xa0<<52) 
  16.    case raceenabled: 
  17.     ... 
  18.    default
  19.     p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32) 
  20.    } 
  21.    hint := (*arenaHint)(mheap_.arenaHintAlloc.alloc()) 
  22.    hint.addr = p 
  23.    hint.next, mheap_.arenaHints = mheap_.arenaHints, hint 
  24.   } 
  25.  } else { 
  26.       ... 
  27.  } 
  • 判斷當前是 64 位還是 32 位的系統。
  • 從 0x7fc000000000~0x1c000000000 開始設置保留地址。
  • 判斷當前 GOARCH、GOOS 或是否開啟了競態檢查,根據不同的情況申請不同大小的連續內存地址,而這里的 p 是即將要要申請的連續內存地址的開始地址。
  • 保存剛剛計算的 arena 的信息到 arenaHint 中。

可能會有小伙伴問,為什么要判斷是 32 位還是 64 位的系統,這是因為不同位數的虛擬內存的尋址范圍是不同的,因此要進行區分,否則會出現高位的虛擬內存映射問題。而在申請保留空間時,我們會經常提到 arenaHint 結構體,它是 arenaHints鏈表里的一個節點,結構如下:

  1. type arenaHint struct { 
  2.  addr uintptr 
  3.  down bool 
  4.  next *arenaHint 
  • addr:arena 的起始地址
  • down:是否最后一個 arena
  • next:下一個 arenaHint 的指針地址

那么這里瘋狂提到的 arena 又是什么東西呢,這其實是 Go 的內存管理中的概念,Go Runtime 會把申請的虛擬內存分為三個大塊,如下:

image

  • spans:記錄 arena 區域頁號和 mspan 的映射關系。
  • bitmap:標識 arena 的使用情況,在功能上來講,會用于標識 arena 的哪些空間地址已經保存了對象。
  • arean:arean 其實就是 Go 的堆區,是由 mheap 進行管理的,它的 MaxMem 是 512GB-1。而在功能上來講,Go 會在初始化的時候申請一段連續的虛擬內存空間地址到 arean 保留下來,在真正需要申請堆上的空間時再從 arean 中取出來處理,這時候就會轉變為物理內存了。

在這里的話,你需要理解 arean 區域在 Go 內存里的作用就可以了。

mmap

我們剛剛通過上述的分析,已經知道 mallocinit 的用途了,但是你可能還是會有疑惑,就是我們之前所看到的 mmap 系統調用,和它又有什么關系呢,怎么就關聯到一起了,接下來我們先一起來看看更下層的代碼,如下:

  1. func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer { 
  2.  p, err := mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0) 
  3.  ... 
  4.  mSysStatInc(sysStat, n) 
  5.  return p 
  6.  
  7. func sysReserve(v unsafe.Pointer, n uintptr) unsafe.Pointer { 
  8.  p, err := mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0) 
  9.  ... 
  10.  
  11. func sysMap(v unsafe.Pointer, n uintptr, sysStat *uint64) { 
  12.  ... 
  13.  munmap(v, n) 
  14.  p, err := mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, -1, 0) 
  15.   ... 

在 Go Runtime 中存在著一系列的系統級內存調用方法,本文涉及的主要如下:

  • sysAlloc:從 OS 系統上申請清零后的內存空間,調用參數是 _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE,得到的結果需進行內存對齊。
  • sysReserve:從 OS 系統中保留內存的地址空間,這時候還沒有分配物理內存,調用參數是 _PROT_NONE, _MAP_ANON|_MAP_PRIVATE,得到的結果需進行內存對齊。
  • sysMap:通知 OS 系統我們要使用已經保留了的內存空間,調用參數是 _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE。

看上去好像很有道理的樣子,但是 mallocinit 方法在初始化時,到底是在哪里涉及了 mmap 方法呢,表面看不出來,如下:

  1. for i := 0x7f; i >= 0; i-- { 
  2.  ... 
  3.  hint := (*arenaHint)(mheap_.arenaHintAlloc.alloc()) 
  4.  hint.addr = p 
  5.  hint.next, mheap_.arenaHints = mheap_.arenaHints, hint 

實際上在調用 mheap_.arenaHintAlloc.alloc() 時,調用的是 mheap 下的 sysAlloc 方法,而 sysAlloc 又會與 mmap 方法產生調用關系,并且這個方法與常規的 sysAlloc 還不大一樣,如下:

  1. var mheap_ mheap 
  2. ... 
  3. func (h *mheap) sysAlloc(n uintptr) (v unsafe.Pointer, size uintptr) { 
  4.  ... 
  5.  for h.arenaHints != nil { 
  6.   hint := h.arenaHints 
  7.   p := hint.addr 
  8.   if hint.down { 
  9.    p -= n 
  10.   } 
  11.   if p+n < p { 
  12.    v = nil 
  13.   } else if arenaIndex(p+n-1) >= 1<<arenaBits { 
  14.    v = nil 
  15.   } else { 
  16.    v = sysReserve(unsafe.Pointer(p), n) 
  17.   } 
  18.   ... 

你可以驚喜的發現 mheap.sysAlloc 里其實有調用 sysReserve 方法,而 sysReserve 方法又正正是從 OS 系統中保留內存的地址空間的特定方法,是不是很驚喜,一切似乎都串起來了。

小結

在本節中,我們先寫了一個測試程序,然后根據非常規的排查思路進行了一步步的跟蹤懷疑,整體流程如下:

  • 通過 top 或 ps 等命令,查看進程運行情況,分析基礎指標。
  • 通過 pprof 或 runtime.MemStats 等工具鏈查看應用運行情況,分析應用層面是否有泄露或者哪兒高。
  • 通過 vmmap 命令,查看進程的內存映射情況,分析是不是進程虛擬空間內的某個區域比較高,例如:共享庫等。
  • 通過 dtruss 命令,查看程序的系統調用情況,分析可能出現的一些特殊行為,例如:在分析中我們發現 mmap 方法調用的比例是比較高的,那我們有充分的理由懷疑 Go 在啟動時就進行了大量的內存空間保留。
  • 通過上述的分析,確定可能是在哪個環節申請了那么多的內存空間后,再到 Go Runtime 中去做進一步的源碼分析,因為源碼面前,了無秘密,沒必要靠猜。

從結論上而言,VSZ(進程虛擬內存大小)與共享庫等沒有太大的關系,主要與 Go Runtime 存在直接關聯,也就是在前圖中表示的運行時堆(malloc)。轉換到 Go Runtime 里,就是在 mallocinit 這個內存分配器的初始化階段里進行了一定量的虛擬空間的保留。

而保留虛擬內存空間時,受什么影響,又是一個哲學問題。從源碼上來看,主要如下:

  • 受不同的 OS 系統架構(GOARCH/GOOS)和位數(32/64 位)的影響。
  • 受內存對齊的影響,計算回來的內存空間大小是需要經過對齊才會進行保留。

總結

我們通過一步步地分析,講解了 Go 會在哪里,又會受什么因素,去調用了什么方法保留了那么多的虛擬內存空間,但是我們肯定會憂心進程虛擬內存(VSZ)高,會不會存在問題呢,我分析如下:

  • VSZ 并不意味著你真正使用了那些物理內存,因此是不需要擔心的。
  • VSZ 并不會給 GC 帶來壓力,GC 管理的是進程實際使用的物理內存,而 VSZ 在你實際使用它之前,它并沒有過多的代價。
  • VSZ 基本都是不可訪問的內存映射,也就是它并沒有內存的訪問權限(不允許讀、寫和執行)。

思考

看到這里舒一口氣,因為 Go VSZ 的高,并不會對我們產生什么非常實質性的問題,但是又仔細一想,為什么 Go 要申請那么多的虛擬內存呢?

總體考慮如下:

  • Go 的設計是考慮到 arena 和 bitmap 的后續使用,先提早保留了整個內存地址空間。
  • Go Runtime 和應用的逐步使用,肯定也會開始實際的申請和使用內存,這時候 arena 和 bitmap 的內存分配器就只需要將事先申請好的內存地址空間保留更改為實際可用的物理內存就好了,這樣子可以極大的提高效能。

參考

High virtual memory allocation by golang

GO MEMORY MANAGEMENT

GoBigVirtualSize

GoProgramMemoryUse

曹大的 Go 程序的啟動流程

全成大佬的 Go 程序是怎樣跑起來的

歐神的 go-under-the-hood

 

責任編輯:武曉燕 來源: 腦子進煎魚了
相關推薦

2019-12-02 14:22:01

浪費云計算支出

2020-04-14 16:03:31

Linux虛擬內存操作系統

2015-09-29 10:12:10

2017-08-14 18:00:13

共享單車摩拜

2023-01-24 16:13:22

編程語言JavaIT

2017-01-21 14:57:43

Linuxsystemd

2023-05-26 00:25:53

2017-09-18 14:39:31

溝通培訓學習

2020-07-13 08:40:21

BAT模具設計

2011-12-31 14:47:10

Web App

2020-08-26 17:03:52

同型號顯卡產品

2013-06-17 10:45:34

2024-04-18 11:53:59

通訊協議網絡

2020-08-10 07:44:13

虛擬內存交換內存Linux

2020-04-24 08:15:51

代碼 if else數組

2022-08-02 09:02:17

虛擬內存操作系統

2022-03-04 22:43:01

5G4G3G

2020-02-16 11:25:22

物聯網硬件技術

2014-07-14 09:51:09

創始人谷歌項目

2010-06-10 17:12:23

Linux 內存監控
點贊
收藏

51CTO技術棧公眾號

男插女视频网站| 国产一区二区自拍| 日本少妇aaa| 精品国产亚洲一区二区三区在线| 亚洲综合色噜噜狠狠| 久久riav二区三区| 亚洲图片视频小说| 在线成人欧美| 一区二区中文字幕| 丰满人妻一区二区三区大胸 | 国内揄拍国内精品少妇国语| 中文字幕一区二区三区人妻| 亚洲成人毛片| 日韩欧美中文字幕在线观看| 91手机视频在线| 秋霞av在线| 国产真实乱偷精品视频免| 欧美性受xxxx白人性爽| 黄色香蕉视频在线观看| 亚洲人成网站77777在线观看| 欧美精三区欧美精三区| 日韩欧美国产免费| 性xxxxfjsxxxxx欧美| 国产欧美一区二区精品性色| 国产精品久久九九| 一本到在线视频| 国产精品夜夜夜| 欧美激情精品久久久久| 久久精品国产亚洲AV成人婷婷| 永久免费精品视频| 欧美精品色一区二区三区| 男人揉女人奶房视频60分| 在线黄色网页| 国产精品麻豆欧美日韩ww| 久久免费看av| 全国男人的天堂网| 国产美女精品人人做人人爽| 国产精品嫩草影院久久久| 99热在线观看免费精品| 激情欧美日韩一区| 欧美成在线观看| 91免费公开视频| 色中色综合网| 国产亚洲精品91在线| 熟女俱乐部一区二区| 日本在线中文字幕一区| 精品黑人一区二区三区久久| 亚洲成人福利视频| 4438五月综合| 制服.丝袜.亚洲.中文.综合| 不卡的在线视频| 成人a在线观看高清电影| 日本道免费精品一区二区三区| 日本丰满少妇xxxx| 懂色av一区| 亚洲第一精品在线| 亚洲一区 在线播放| a视频在线观看| 日韩一区欧美小说| 欧洲美女和动交zoz0z| 久草中文在线| 亚洲精品五月天| 国产在线无码精品| 免费毛片在线看片免费丝瓜视频 | 老司机av福利| 韩国中文字幕在线| 亚洲少妇30p| 日本中文字幕一级片| 日本在线观看高清完整版| 亚洲国产精品嫩草影院| 男女猛烈激情xx00免费视频| 这里有精品可以观看| 日韩欧美极品在线观看| 九九视频精品在线观看| 亚洲国产综合在线观看| 日韩欧美在线观看一区二区三区| 中文字幕18页| 天天躁日日躁狠狠躁欧美| 伊人伊人伊人久久| 天堂网avav| 激情婷婷久久| 日韩av电影免费观看高清| 在线观看中文字幕av| 国产精品中文有码| 精品欧美一区二区精品久久| 成人精品一区二区三区免费 | 欧美色欧美亚洲另类七区| 成人免费视频| 一区二区三区成人| 午夜精品久久久内射近拍高清 | 在线亚洲一区二区| 国产精欧美一区二区三区白种人| 在这里有精品| 亚洲午夜性刺激影院| 日韩a级片在线观看| 一本色道88久久加勒比精品| 国产精品欧美日韩久久| 亚洲国产精品欧美久久| 久久久精品人体av艺术| 艳母动漫在线观看| 丝袜老师在线| 日韩亚洲欧美一区二区三区| 成人网站免费观看| 香蕉综合视频| 69影院欧美专区视频| 国产又粗又猛又爽又黄视频| www..com久久爱| 亚洲精品国产精品国自产观看| 最新国产露脸在线观看| 欧美视频一区二区三区…| 亚洲欧美手机在线| 台湾佬综合网| 欧美久久久精品| 日韩一级片中文字幕| 国产精品77777| 欧美日韩喷水| 精精国产xxxx视频在线中文版 | 伊人久久成人网| av在线不卡电影| 亚洲午夜精品久久久久久浪潮| av中文字幕在线看| 555夜色666亚洲国产免| 手机免费看av| 亚洲日本视频| 91精品国产91久久久久青草| 黄色网址在线播放| 精品欧美一区二区三区| 伊人成人免费视频| 日韩一区二区中文| 日韩av电影在线播放| 可以免费看毛片的网站| 亚洲欧美日本韩国| 国产精品一区二区小说| 欧美日韩爱爱| 2019中文字幕全在线观看| 99热这里只有精品3| 中文字幕精品三区| 国产av无码专区亚洲精品| 成人精品动漫一区二区三区| 超碰日本道色综合久久综合 | 欧美成人video| 91麻豆精品久久毛片一级| 一区免费视频| 高清不卡一区二区三区| www在线视频| 91精品国产综合久久福利软件| 精品伦精品一区二区三区视频密桃| 欧美va亚洲va日韩∨a综合色| 国产人妖伪娘一区91| 91免费在线| 日本韩国一区二区三区视频| 欧美激情aaa| 美女日韩在线中文字幕| 蜜桃久久精品乱码一区二区| h片在线观看| 欧美精品一区二区三区视频| 青春草免费视频| 麻豆精品视频在线观看视频| 一本久道久久综合| 99re8精品视频在线观看| 北条麻妃一区二区三区中文字幕| 中文字幕网址在线| 国产精品成人午夜| 婷婷激情小说网| 欧美涩涩视频| 久久av二区| 欧美性xxx| 中文字幕av日韩| 国产美女自慰在线观看| 一区二区三区中文免费| 最新版天堂资源在线| 国产精品嫩草99av在线| 欧美一区二区三区成人久久片| 午夜无码国产理论在线| 久久精品视频99| 丰满少妇高潮在线观看| 韩曰欧美视频免费观看| 在线国产视频一区| 国产一区二区三区香蕉| 僵尸世界大战2 在线播放| 香蕉久久99| 国产自产女人91一区在线观看| www视频在线免费观看| 亚洲激情电影中文字幕| 日韩综合在线观看| 亚洲视频狠狠干| 三叶草欧洲码在线| 美女网站视频久久| www.在线观看av| 国产aⅴ精品一区二区三区久久| 国产精品永久免费观看| 牛牛电影国产一区二区| 亚洲天堂影视av| av免费观看网址| 欧美性感美女h网站在线观看免费| 男人天堂资源网| 成人激情小说网站| 免费看黄色一级大片| 欧美日韩免费| 日韩福利在线| 在线精品自拍| 国产精品老女人视频| 亚洲卡一卡二| 国产亚洲精品一区二区| 亚洲第一色网站| 欧美亚洲国产怡红院影院| 久久网一区二区| 亚洲国产高清不卡| 北京富婆泄欲对白| 狠狠色伊人亚洲综合成人| 久久国产亚洲精品无码| 91久久高清国语自产拍| 久久久久久久有限公司| 国产精品麻豆| 国产精品电影在线观看| 91老司机福利在线| 久久夜精品香蕉| 黄色软件在线观看| 日韩的一区二区| 不卡的日韩av| 欧美日韩精品一区二区三区| 欧美福利视频一区二区| 亚洲免费观看高清完整| 国产午夜福利一区| 91丨九色丨国产丨porny| 蜜臀aⅴ国产精品久久久国产老师| 久草在线在线精品观看| aⅴ在线免费观看| 99成人免费视频| 中文精品无码中文字幕无码专区| 欧美高清视频手机在在线| 欧洲精品在线一区| 色婷婷狠狠五月综合天色拍| 国产欧美一区二区三区另类精品 | 国产精品一区二区av| 美女精品视频在线| 成人日韩av在线| 四虎地址8848精品| 国产精品自产拍高潮在线观看| 欧美电影免费观看高清完整| 91超碰caoporn97人人| 91九色美女在线视频| 欧美激情视频在线| 日本不卡影院| 欧美精品成人91久久久久久久| 亚洲第一色av| 国产又色又爽又黄刺激在线视频| 久久精品欧美视频| 国产在线高潮| 欧美成人黑人xx视频免费观看| 免费网站免费进入在线| 日韩视频免费在线观看| 浪潮av一区| 欧美成人午夜免费视在线看片| 国产黄大片在线观看画质优化| 久久亚洲精品一区| 在线视频观看国产| 久久久久国产一区二区三区| 搞黄网站在线看| 97在线观看视频国产| 手机在线观看av| 国产91免费观看| 69堂精品视频在线播放| 国产免费久久av| 国产精品亚洲综合在线观看| 91久久久久久久一区二区| 91国产一区| 成人看片在线| 日韩高清三区| 日本婷婷久久久久久久久一区二区 | 欧美专区中文字幕| 日韩av超清在线观看| 国产伦精品一区二区三区精品视频| 欧美黑粗硬大| 97久久人人超碰caoprom欧美| 中文字幕一区日韩精品| 久久超碰亚洲| 成人系列视频| 成人午夜免费剧场| 国产精品普通话对白| 亚洲精品久久久中文字幕| 国产一区不卡在线| 中国极品少妇videossexhd| 2023国产精品自拍| 蜜桃av免费在线观看| 夜夜爽夜夜爽精品视频| 亚洲熟女综合色一区二区三区| 欧美综合久久久| 国产精品丝袜黑色高跟鞋| 精品国产一区二区三区忘忧草 | 国产精品久久免费视频 | 神马久久一区二区三区| 一区二区三区在线视频111| 欧美日韩国产高清| 久久久久久久久久久久久久国产| 国内精品视频一区二区三区八戒| 亚洲欧美日韩偷拍| 亚洲国产成人私人影院tom| 岛国毛片在线观看| 日本丶国产丶欧美色综合| www香蕉视频| 亚洲午夜久久久影院| 日韩特级毛片| 国产精品视频1区| 国产伦乱精品| 亚洲一区尤物| 香蕉av777xxx色综合一区| 免费高清视频在线观看| 国产亚洲人成网站| 久久久久久久久久久网| 欧美日韩免费一区二区三区| 日本激情一区二区| 毛片精品免费在线观看| 日韩精选视频| 精品一区在线播放| 中文字幕一区二区三区在线视频 | 相泽南亚洲一区二区在线播放 | 国产欧美久久久精品免费| 亚洲人成网站777色婷婷| 牛牛精品在线视频| 亚洲影院高清在线| 久久网站免费观看| 国产成人精品无码播放| 不卡视频免费播放| 黄色一级视频免费| 欧美精品乱人伦久久久久久| 国产裸舞福利在线视频合集| 欧美一区第一页| 国产美女撒尿一区二区| 精品视频在线观看一区二区| 激情都市一区二区| 永久免费未视频| 欧美日韩一区中文字幕| 懂色一区二区三区| 欧美怡春院一区二区三区| 欧美变态网站| 日韩a∨精品日韩在线观看| 国产不卡在线视频| 成人免费毛片东京热| 制服丝袜激情欧洲亚洲| 拍真实国产伦偷精品| 国产精品日韩在线一区| 欧美精品久久久久久| 中文字幕无码不卡免费视频| 久久亚洲一级片| 800av免费在线观看| 日韩风俗一区 二区| 蜜桃视频在线观看播放| 久久草.com| 麻豆精品91| 亚洲精品乱码久久久久久久久久久久| 精品久久久久久久久久久久久| 好男人在线视频www| 97国产suv精品一区二区62| 精品自拍偷拍| 中国丰满人妻videoshd | 91麻豆精品国产91久久久久久久久| 2017亚洲天堂1024| 成人在线中文字幕| 欧美一区亚洲| 日本久久久久久久久久| 偷窥国产亚洲免费视频| 青青草在线播放| 国产精品96久久久久久| 日韩欧美高清| a级大片免费看| 午夜精品福利一区二区蜜股av| 午夜福利视频一区二区| 国产不卡在线观看| 欧美成人精品一区二区三区在线看| 国内自拍视频网| 成人免费在线播放视频| 成 人片 黄 色 大 片| 91精品成人久久| 日韩久久电影| 最新版天堂资源在线| 日韩欧美高清在线视频| 快射av在线播放一区| 91精品婷婷国产综合久久蝌蚪| 999亚洲国产精| 人成免费在线视频| 日韩视频免费观看高清在线视频| 妞干网免费在线视频| 一区不卡字幕| 成人午夜视频在线| 国产suv精品一区二区33| 日韩在线观看视频免费| 高清日韩中文字幕| 亚洲xxxx2d动漫1| 亚洲一区免费视频| 精品999视频| yellow视频在线观看一区二区| 亚洲综合日韩| 亚洲熟女www一区二区三区| 日韩激情视频在线| 中文幕av一区二区三区佐山爱| 欧美精品自拍视频| 亚洲同性同志一二三专区| 三级无遮挡在线观看| 亚洲xxxx18|