成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

先聊聊「內存分配」,再聊聊Go的「逃逸分析」

開發 后端
通過本文的介紹,相信你一定加深了堆棧的理解;搞清楚逃逸分析的作用和原理之后能夠指導我們寫出更優雅的代碼。

要搞清楚GO的逃逸分析一定要先搞清楚內存分配和堆棧:

內存分配既可以分配到堆中,也可以分配到棧中。

什么樣的數據會被分配到棧中,什么樣的數據又會被分配到堆中呢?

GO語言是如何進行內存分配的呢?其設計初衷和實現原理是什么呢?

我們先來聊一下內存管理、堆、棧的知識點:

內存管理

內存管理主要包括兩個動作:分配與釋放。逃逸分析就是服務于內存分配。

在Go中,棧的內存是由編譯器自動進行分配和釋放,棧區往往存儲著函數參數、局部變量和調用函數幀,它們隨著函數的創建而分配,函數的退出而銷毀。

一個goroutine對應一個棧,棧是調用棧(call stack)的簡稱。一個棧通常又包含了許多棧幀(stack frame),它描述的是函數之間的調用關系,每一幀對應一個尚未返回的函數調用,它本身也是以棧形式存放數據。

與棧不同的是,應用程序在運行時只會存在一個堆。

我們可以簡單理解為:我們用GO語言開發過程中,要考慮的內存管理只是針對堆內存而言的。

程序在運行期間可以主動從堆上申請內存,這些內存通過Go的內存分配器分配,并由垃圾收集器回收。

堆和棧的對比

加鎖

  • 棧不需要加鎖:棧是每個goroutine獨有的,這就意味著棧上的內存操作是不需要加鎖的。
  • 堆有時需要加鎖:堆上的內存,有時需要加鎖防止多線程沖突

延伸知識點:為什么堆上的內存有時需要加鎖?而不是一直需要加鎖呢?

因為Go的內存分配策略學習了TCMalloc的線程緩存思想,他為每個處理器P分配了一個mcache,從mcache分配內存也是無鎖的

性能

  • 棧內存管理 性能好:棧上的內存,它的分配與釋放非常高效的。簡單地說,它只需要兩個CPU指令:一個是分配入棧,另外一個是棧內釋放。只需要借助于棧相關寄存器即可完成。
  • 堆內存管理 性能差:對于程序堆上的內存回收,還需要通過標記清除階段,例如Go采用的三色標記法。

緩存策略

  • 棧緩存性能更好
  • 堆緩存性能較差

原因是:棧內存能更好地利用CPU的緩存策略,因為棧空間相較于堆來說是更連續的。

逃逸分析

上面說了這么多堆和棧的知識點,目的是為了讓大家更好的理解逃逸分析。

正如上面講的,相比于把內存分配到堆中,分配到棧中優勢更明顯。

Go語言也是這么做的:Go編譯器會盡可能將變量分配到到棧上。

但是,當編譯器無法證明函數返回的變量有沒有被引用時,編譯器就必須在堆上分配該變量,以此避免懸掛指針(dangling pointer)的問題。

另外,如果局部變量占用內存非常大,也會將其分配在堆上。

Go是如何確定內存是分配到棧上還是堆上的呢?

答案就是:逃逸分析。

編譯器通過逃逸分析技術去選擇堆或者棧,逃逸分析的基本思想如下:檢查變量的生命周期是否是完全可知的,如果通過檢查,則在棧上分配。否則,就是所謂的逃逸,必須在堆上進行分配。

逃逸分析原則

Go語言雖然沒有明確說明逃逸分析原則,但是有以下幾點準則,是可以參考的。

  • 不同于JAVA JVM的運行時逃逸分析,Go的逃逸分析是在編譯期完成的:編譯期無法確定的參數類型必定放到堆中;
  • 如果變量在函數外部存在引用,則必定放在堆中;
  • 如果變量占用內存較大時,則優先放到堆中;
  • 如果變量在函數外部沒有引用,則優先放到棧中;

逃逸分析舉例

我們使用這個命令來查看逃逸分析的結果:go build -gcflags '-m -m -l'

1.參數是interface類型

package main

import "fmt"

func main() {
a := 666
fmt.Println(a)
}

運行結果

圖片

原因分析

因為Println(a ...interface{})的參數是interface{}類型,編譯期無法確定其具體的參數類型,所以內存分配到堆中。

圖片

2. 變量在函數外部有引用

package main

func test() *int {
a := 10
return &a
}

func main() {
_ = test()
}

運行結果

圖片

原因分析

變量a在函數外部存在引用。

我們來分析一下執行過程:當函數執行完畢,對應的棧幀就被銷毀,但是引用已經被返回到函數之外。如果這時外部通過引用地址取值,雖然地址還在,但是這塊內存已經被釋放回收了,這就是非法內存。

為了避免上述非法內存的情況,在這種情況下變量的內存分配必須分配到堆上。

3. 變量內存占用較大

package main

func test() {
a := make([]int, 10000, 10000)
for i := 0; i < 10000; i++ {
a[i] = i
}
}

func main() {
test()
}

運行結果

圖片

原因分析

我們定義了一個容量為10000的int類型切片,發生了逃逸,內存分配到了堆上(heap)。

注意看:

我們再簡單修改一下代碼,將切片的容量和長度修改為1,再次查看逃逸分析的結果,我們發現,沒有發生逃逸,內存默認分類到了棧上。

圖片

所以,當變量占用內存較大時,會發生逃逸分析,將內存分配到堆上。

4. 變量大小不確定時

我們再簡單修改一下上面的代碼:

package main

func test() {
l := 1
a := make([]int, l, l)
for i := 0; i < l; i++ {
a[i] = i
}
}

func main() {
test()
}

運行結果

圖片

原因分析

我們通過控制臺的輸出結果可以很明顯的看出:發生了逃逸,分配到了heap堆中。

原因是這樣的:

我們雖然在代碼段中給變量 l 賦值了1,但是編譯期間只能識別到初始化int類型切片時,傳入的長度和容量是變量l,編譯期并不能確定變量l的值,所以發生了逃逸,會把內存分配到堆中。

思考題

好了,我們舉了4個逃逸分析的經典案例,相信聰明的你已經理解了逃逸分析的作用和發生逃逸的場景。

我們來想一下,在理解逃逸分析的原理之后,在開發的過程中如何更好的編碼,進而提高程序的效率,更好的利用內存呢?

如何實踐?

理解逃逸分析一定能幫助我們寫出更好的程序。知道變量分配在棧堆之上的差別后,我們就要盡量寫出分配在棧上的代碼。因為堆上的變量變少后,可以減輕內存分配的開銷,減小GC的壓力,提高程序的運行速度。

但是我們也要有過猶不及的指導思想。

我認為沒有一成不變的開發模式,我們一定是在不斷的需求變化,業務變化中求得平衡的:

舉個例子

舉個日常開發中函數傳參的例子:

有些場景下我們不應該傳遞結構體指針,而應該直接傳遞結構體。

為什么會這樣呢?雖然直接傳遞結構體需要值拷貝,但是這是在棧上完成的操作,開銷遠比變量逃逸后動態地在堆上分配內存少的多。

當然這種做法不是絕對的,要根據場景去分析:

  • 如果結構體較大,傳遞結構體指針更合適,因為指針類型相比值類型能節省大量的內存空間
  • 如果結構體較小,傳遞結構體更適合,因為在棧上分配內存,可以有效減少GC壓力

總結

通過本文的介紹,相信你一定加深了堆棧的理解;搞清楚逃逸分析的作用和原理之后能夠指導我們寫出更優雅的代碼。

我們在日常開發中,要根據實際場景考慮,如何將內存盡量分配到棧中,減少GC的壓力,提高性能。

如何找到應用開發效率、程序運行效率、對機器的壓力及負載的平衡點,是程序員進階之旅中的必修課。

本文轉載自微信公眾號「 程序員升級打怪之旅」,作者「王中陽Go」,可以通過以下二維碼關注。

轉載本文請聯系「 程序員升級打怪之旅」公眾號。

責任編輯:武曉燕 來源: 程序員升級打怪之旅
相關推薦

2023-01-10 09:18:37

Go內存分配逃逸

2021-12-16 06:52:33

C語言內存分配

2023-01-28 08:32:04

Go內存分配

2017-03-16 13:17:54

TDD代碼開發

2023-03-26 23:47:32

Go內存模型

2022-10-17 09:03:52

2017-03-16 13:28:34

TDD代碼軟件架構

2021-02-22 09:30:09

go開發環境桌面系統

2021-01-07 07:53:10

JavaScript內存管理

2022-02-11 09:31:23

IPV4IP地址IANA

2021-05-30 19:29:12

內存Go語言

2022-12-12 08:42:06

Java對象棧內存

2020-05-06 22:07:53

UbuntuLinux操作系統

2024-04-07 11:33:02

Go逃逸分析

2023-01-30 23:04:10

B-Treegolang優化

2022-09-28 11:34:27

用戶行為數據業務

2021-08-16 06:56:21

Slice數組類型內存

2024-01-15 06:42:00

高并發熱點賬戶數據庫

2021-03-28 20:58:25

Go語言線程

2021-04-29 09:02:44

語言Go 處理
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91国产精品在线 | 亚洲欧美综合精品久久成人 | 欧美在线视频一区 | 欧美激情亚洲天堂 | 婷婷五月色综合 | 不卡的av在线 | 国产一区二区观看 | 成人免费一区二区三区视频网站 | 超碰婷婷 | 日本一区二区三区在线观看 | 国产高清在线观看 | 一级做a | 国产精品高清在线 | 日韩在线h | 91免费在线播放 | 中文字幕国产精品视频 | 成人午夜毛片 | 久久人爽爽人爽爽 | 伊人网综合在线 | 99久久久久久 | 欧美精品在线一区二区三区 | 粉嫩av| 国产精品99久久久久久www | 日韩精品国产精品 | 国产欧美日韩一区二区三区在线观看 | 美国一级黄色片 | 在线观看欧美日韩视频 | 一级a性色生活片久久毛片波多野 | 精品综合久久 | 91福利影院 | 99国产精品99久久久久久粉嫩 | 日韩h| 亚洲人成人一区二区在线观看 | 久久网站免费视频 | 日韩视频在线免费观看 | 亚洲区在线 | 欧美国产一区二区 | 午夜影院在线观看 | 一级片成人 | 精品日韩| 日本在线你懂的 |