網站首頁 編程語言 正文
棧內存-協程棧-調用棧
為什么go的棧是在堆上?
go 協程棧的位置: go的協程棧位于go的堆內存,go 的gc 也是對堆上內存進行GC, go堆內存位于操作系統虛擬內存上, 記錄局部變量,傳遞參數和返回值 ,go 使用的參數拷貝傳遞,如果傳遞的值比較大 注意傳遞其指針
go 參數傳遞 使用 值傳遞, 也就是說傳遞結構體時候,拷貝結構體的指針,傳遞結構體指針時候 拷貝的結構體指針 所以對于 只讀參數,不進行修改,最好傳遞結構體指針
協程棧的空間不夠大 怎么辦?
本地變量太大,棧幀太多
逃逸分析
不是所有的變量都放在協程棧上,棧幀回收后,需要繼續使用的變量,或者 太大的變量,分為指針逃逸,空接口逃逸和大變量逃逸,從棧逃逸分配到堆空間上
指針逃逸 (函數返回的指針被其他使用)
func a() *int { v :=0 return &v // 導致 局部變量會分配在堆行 不會分配棧上 }
空接口逃逸(函數的參數是interface{} 函數的實參很可能會逃逸,主要因為interface{} 類型函數往往會使用反射)
fmt.Println(i) // 入參屬于interface{} 空接口, 是否有反射查看值是什么類型 逃逸到堆上
大變量逃逸(過大變量導致的空間不足,超過64KB的變量會逃逸)
// 解決協程的棧空間不足
調用棧幀太多(棧擴容)
- 解決方式 進行棧擴容,Go的棧初始空間為2KB
- 在函數調用前判斷棧空間morestack
- 早期使用分段棧(go 1.13) 在邏輯上連接,優點沒有空間浪費,棧指針會在不連續的空間跳轉,后期 連續棧,缺點 伸縮時候開銷大,擴容為原來2倍, 使用比例不足1/4, 變為原來的 1/2
go 堆內存
操作系統的虛擬內存:操作系統給應用提供的虛擬的內存的空間,背后也是物理內存或者磁盤
go 使用 heapArena每次申請虛擬內存單元 64MB,所有的heapArena 組成 堆內存
線性分配據或者鏈表分配出現空間碎片,所有go 語言中使用分級分配,避免內存的碎片化,每個內存進行分級思想, mspan n內存管理單元
按照需求進行分級分配,runtime.sizeclass.go 進行分配, 總共有68 個級別。
其中 136 個span , mcentral 屬于鏈接頭,其中 68個需要GC掃描,其他68個不需要GC掃描。 mcentral 的屬于中心索引,使用互斥鎖保護,在高并發的場景下 鎖沖突嚴重,參考GMP模型,增加線程的本地緩存。
- Go 模仿TCmalloc ,建立自己的堆內存架構
- 使用heapArena 向操作系統申請內存,以mspan 為單位,防止碎片化
- mcentral 是mspan 的中心索引
- 使用mcache 本地緩存 大大降低 鎖競爭問題
堆如何進行分配
- Tiny 微對象(0,16B)無指針 – 分配到普通mspan(class 1 - class 67) --將多個微級對象合并成16Byte
- Small 對象[16B, 32K] – 定制作mspan (class 0)
- Large 大對象(32KB, +)
- heapArena 不足的化 會自動申請擴容
go 語言對象的垃圾回收
- 標記-清除
- 標記-整理 (go 語言使用分級分配 不需要標記整理)
- 標記-復制 (只有用內存進行復制,但是空間浪費非常大,Java的新生代) 總結: Go 堆內存的獨特方式 進行標記清除掉,如何尋找有用?
- Gc的起點: 1. 被棧上的指針引用 2.被全局變量引用 3.被寄存器中指針引用
- Root 節點進行廣度優先策略進行搜索(可達性分析標記方法)
- 暫停所有其他協程,進行可達性分析,找到無引用的GC 屬于串行GC 屬于在OLD version 中
如何減少GC對性能的分析
如何進行并行GC 提升性能?
難點在于如何進行標記階段,go 語言采用的 三色標記方法
- 黑色: 表示已經分析掃描,有用
- 灰色: 有用,還沒進行分析掃描 DFS代替隊列
- 白色: 暫時無用
當三色標記結束后只有黑色的對象,下一次開啟恢復成 白色
并發標記的問題(刪除)-- 在GC時候 進行對象的指針的變動,針對 并發標記問題 使用 Yuasa 刪除屏障, 強制將釋放的C指針變成灰色,避免 在GC過程中被粗我?標記
Yuasa 刪除屏障(s釋放的指針進行強制為灰色)
1. 刪除屏障可以杜絕在GC標記中刪除的問題 ,但是也無法解決并發標記的插入問題
針對插入屏障 使用 Dijkstra 插入屏障 并發標記過程中 將C進行強制置灰,當并發標記過程,新指針指向新的對象,新增的依賴對象 防止錯誤的GC
混合屏障
被刪除的堆對象標記成為灰色
被添加的堆對象標記成為灰色
并發垃圾回收關鍵在于標記安全,兼顧的安全的效率
GC 優化效率
GC觸發的時機
系統定時觸發
g0 協程內的sysmon 定時檢查 ,在2min 內 forcegcperiod 沒有過GC,觸發,謹慎調整
用戶顯示觸發
調用runtime.gc 并不推薦
申請內存觸發
給申請對象的時候伴隨著GC
GC優化原則
盡量少在堆上產生垃圾
內存池化(channel 中 環形池)
減少逃逸 (fmt 包, 返回了指針不是拷貝)
使用空結構體 (不占用空結構體,使用channel 傳遞空結構體)
使用如下的方式 查看內存
$env:GODEBUG="gctrace=1"
原文鏈接:https://blog.csdn.net/qq_27217017/article/details/126807349
相關推薦
- 2023-05-15 shell?提取文件名和目錄名的方法實現_linux shell
- 2023-10-14 SQL Server 執行sql報錯'sys.sp_OACreate' 的訪問
- 2022-07-26 使用Docker將容器目錄掛載到主機上的實現方法_docker
- 2022-10-19 為什么不要在?Flutter?中使用全局變量_Android
- 2024-03-08 Spring bean的實例化方式之靜態工廠和實例工廠的區別
- 2022-04-30 Python中類變量和實例變量的區別_python
- 2022-03-14 文件上傳錯誤the request doesn't contain a multipart/form
- 2022-03-26 .NET?6中使用DateOnly和TimeOnly類型_ASP.NET
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支