網(wǎng)站首頁 編程語言 正文
概念
當(dāng)一個(gè)對(duì)象的指針在被多個(gè)方法或者線程引用,稱為逃逸分析, 逃逸分析決定一個(gè)變量分配在堆上還是棧上, 當(dāng)然是否發(fā)生逃逸是由編譯器決定的
分配棧和堆上變量的問題
1.局部變量在棧上(靜態(tài)分配),函數(shù)執(zhí)行完畢后,自動(dòng)被棧回收,導(dǎo)致其他對(duì)此變量引用出現(xiàn)painc null 指針異常, 棧用戶態(tài)實(shí)現(xiàn)goroutine 作為執(zhí)行上下文
2.將變量 new 方式分配在堆上(動(dòng)態(tài)分配),堆上有個(gè)特點(diǎn),變量不會(huì)被刪除,但是會(huì)造成內(nèi)存異常
// 如下代碼導(dǎo)致 程序崩潰, 調(diào)用棧獲取危險(xiǎn)的懸掛指針 int *foo ( void) { int t = 3; return &t; }
1. 棧上分配內(nèi)存好處: 一般棧內(nèi)存 2-4 MB
a. 回收快: 減少GC壓力,當(dāng)函數(shù)返回回收資源。不需要標(biāo)記清除
b. 分配快棧分配比堆快,不會(huì)有內(nèi)存碎片
c. 并發(fā)快, 清除同步,如果定義對(duì)象上有同步鎖,卻只有一個(gè)線程訪問,此時(shí)逃逸分析機(jī)器碼 去掉同步鎖
總結(jié): 逃逸分析目標(biāo):盡可能的使用棧分配內(nèi)存 go build -gcflags ‘-m -N -l’ 方式編譯逃逸分析結(jié)果
逃逸分析準(zhǔn)則
如果一個(gè)函數(shù)返回對(duì)變量的引用,那么他就發(fā)生逃逸
- 函數(shù)外部沒有引用,優(yōu)先分配到棧中(指向棧對(duì)象指針不能存在堆中)-- 該指針指向無效值或錯(cuò)誤的內(nèi)存值
- 函數(shù)外部存在引用,必定分配到堆中(指向棧對(duì)象指針不能在棧對(duì)象回收后存活-- 指向的內(nèi)存不合法)
CCN_ProLang/CoreGo/GoreGo 下面有對(duì)應(yīng)的文檔參考
逃逸分析大致思路
1.最重要函數(shù) escape.go
$GOROOT/src/cmd/compile/internal/gc/escape.go
1. 首先構(gòu)建一個(gè)有向無環(huán)圖加權(quán)圖,頂點(diǎn)(語句和表達(dá)式分配的變量),邊(代表變量之間的賦值關(guān)系)
2. 遍歷該有向加權(quán)圖,圖中違反上面兩個(gè)不變條件的賦值路徑,算法還記錄每個(gè)函數(shù)的參數(shù)到堆的數(shù)據(jù)流和其返回值的數(shù)據(jù)流
權(quán)重
// p =&q -1 // 最低值
// p =q 0
// p = *q // 解引用 1
// p = **q 2
示例: root =&L , L 節(jié)點(diǎn)的指針指向root, 因此 root有一條邊,src 就是L,該權(quán)重就是 -1
3. 逃逸分析: 分析 分配內(nèi)存地方與使用 是否發(fā)生逃逸
4. go build -gcflags = "-m -m -m -m -W -W -N -l"
1. 當(dāng)函數(shù)中變量返回值, 它將不可能分配在棧上
2.在循環(huán)內(nèi)被重新賦值的變量大部分場景分配在堆上
3.在閉包外聲明的變量在閉包內(nèi)賦值失效后,需要分配在堆上
是否發(fā)生逃逸,這一點(diǎn)使用編譯器決定的。導(dǎo)致后果:1. GC頻繁導(dǎo)致CPU壓力大 2.導(dǎo)致性能下降很大
1. 一些逃逸案例: 2. 函數(shù)返回變量取地址 導(dǎo)致逃逸 func GetUserInfo(userInfo UserData) *UserData{ // 編譯器判斷外部使用 發(fā)生逃逸 ,傳入的實(shí)參對(duì)象 取地址類似復(fù)制一份 return &userInfo } //修改 將入?yún)⑿薷某芍羔? 中間沒有新結(jié)構(gòu)體沒有變化 沒有發(fā)生逃逸 func GetUserInfo(userInfo *UserData) *UserData { return userInfo } 案例二:不確定類型逃逸 func MyPrintLn(one interface{}) (n int, err error){ var userInfo = new(User) userInfo.name = one // 泛型賦值逃逸 類型轉(zhuǎn)換時(shí)候發(fā)生逃逸 return } 變量確定具體類型 示例三: 間接變量賦值 閉包 var { UserOne User // 值對(duì)象 userTwo = new(User) // 引用對(duì)象 } userOne.name = "one" // 不逃逸 userTwo.name = "two" // 逃逸 userOne.age = new(int) // 不逃逸 userTwo.age = new(int) // 逃逸 引用對(duì)象在進(jìn)行引用對(duì)象 只能分配堆上 引用對(duì)象: 編譯器先分析器userTwo 對(duì)象分配到堆上,成員變量name,age 引用類型,保證不出現(xiàn)在棧上 導(dǎo)致對(duì)象userTwo 被回收 所有 name,age 需要逃逸 優(yōu)化建議: 不要將引用對(duì)象賦值給引用對(duì)象
總結(jié)
必然不會(huì)發(fā)生逃逸的情況:
1. 指針被沒有發(fā)生逃逸的變量引用
2. 僅僅在函數(shù)被對(duì)變量進(jìn)行取地址操作,沒有將指針傳出
一定逃逸
構(gòu)造函數(shù)new/make 返回的指針變量一定逃逸
2. 被已經(jīng)逃逸指針變量引用指針,一定發(fā)生逃逸
3.指針類型是slice,map,chan 引用指針一定發(fā)生逃逸
Maybe 逃逸
將指針作為入?yún)鹘o別的函數(shù),這里看指針在被傳入函數(shù)的處理過程,如果發(fā)生上邊三種情況會(huì)逃逸,否則不會(huì)
原文鏈接:https://blog.csdn.net/qq_27217017/article/details/125833466
相關(guān)推薦
- 2022-11-21 小白也能看懂的Redis遍歷鍵和數(shù)據(jù)庫管理詳解_Redis
- 2022-12-21 Redis?RDB與AOF持久化方式詳細(xì)講解_Redis
- 2023-06-21 C++析構(gòu)函數(shù)內(nèi)部工作機(jī)制詳解_C 語言
- 2023-05-10 Python中的SOLID原則實(shí)例詳解_python
- 2022-08-05 基于python詳解PyScript到底是什么_python
- 2022-12-01 C/C++細(xì)數(shù)宏與函數(shù)有那些區(qū)別_C 語言
- 2022-05-19 Python學(xué)習(xí)之異常斷言詳解_python
- 2022-03-16 C語言下快速排序(挖坑法)詳解_C 語言
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支