日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql 变量生命周期_Go: 延长变量的生命周期

發布時間:2024/9/27 数据库 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 变量生命周期_Go: 延长变量的生命周期 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

![Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/00.png)

本文基于 Go 1.13。

在 Go 中,我們不需要自己管理內存分配和釋放。然而,有些時候我們需要對程序進行更細粒度的控制。Go 運行時提供了很多種控制運行時狀態及其與內存管理器之間相互影響的方式。本文中,我們來審查讓變量不被 GC 回收的能力。

## 場景

我們來看一個基于 [Go 官方文檔](https://golang.org/pkg/runtime/#KeepAlive) 的例子:

```go

type File struct { d int }

func main() {

p := openFile("t.txt")

content := readFile(p.d)

println("Here is the content: "+content)

}

func openFile(path string) *File {

d, err := syscall.Open(path, syscall.O_RDONLY, 0)

if err != nil {

panic(err)

}

p := &Fileozvdkddzhkzd

runtime.SetFinalizer(p, func(p *File) {

syscall.Close(p.d)

})

return p

}

func readFile(descriptor int) string {

doSomeAllocation()

var buf [1000]byte

_, err := syscall.Read(descriptor, buf[:])

if err != nil {

panic(err)

}

return string(buf[:])

}

func doSomeAllocation() {

var a *int

// memory increase to force the GC

for i:= 0; i < 10000000; i++ {

i := 1

a = &i

}

_ = a

}

```

[源碼地址](https://gist.githubusercontent.com/blanchonvincent/a247b6c2af559b62f93377b5d7581b7f/raw/6488ec2a36c28c46f942b7ac8f24af4e75c19a2f/main.go)

這個程序中一個函數打開文件,另一個函數讀取文件。代表文件的結構體注冊了一個 finalizer,在 gc 釋放結構體時自動關閉文件。運行這個程序,會出現 panic:

```bash

panic: bad file descriptor

goroutine 1 [running]:

main.readFile(0x3, 0x5, 0xc000078008)

main.go:42 +0x103

main.main()

main.go:14 +0x4b

exit status 2

```

下面是流程圖:

- 打開文件,返回一個文件描述符

- 這個文件描述符被傳遞給讀取文件的函數

- 這個函數首先做一些繁重的工作:

![圖 01](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/01.png)

allocate 函數觸發 gc:

![02.png](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/02.png)

因為文件描述符是個整型,并以副本傳遞,所以打開文件的函數返回的結構體 `*File*` 不再被引用。Gc 把它標記為可以被回收的。之后觸發這個變量注冊的 finalizer,關閉文件。

然后,主協程讀取文件:

![03.png](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/03.png)

因為文件已經被 finalizer 關閉,所以會出現 panic。

## 讓變量不被回收

`runtime` 包暴露了一個方法,用來在 Go 程序中避免出現這種情況,并顯式地聲明了讓變量不被回收。在運行到這個調用這個方法的地方之前,gc 不會清除指定的變量。下面是加了對這個方法的調用的新代碼:

![04.png](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/04.png)

在運行到 `keepAlive` 方法之前,gc 不能回收變量 `p`。如果你再運行一次程序,它會正常讀取文件并成功終止。

## 追本逐源

`keepAlive` 方法本身沒有做什么:

![05.png](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/05.png)

運行時,Go 編譯器會以很多種方式優化代碼:函數內聯,死碼消除,等等。這個函數不會被內聯,Go 編譯器可以輕易地探測到哪里調用了 `keepAlive`。編譯器很容易追蹤到調用它的地方,它會發出一個特殊的 SSA 指令,以此來確保它不會被 gc 回收。

![06.png](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/06.png)

在生成的 SSA 代碼中也可以看到這個 SSA 指令:

![07.png](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/07.png)

在我的文章 [Go 編譯器概述](https://medium.com/a-journey-with-go/go-overview-of-the-compiler-4e5a153ca889) 中你可以看到更多關于 Go 編譯器和 SSA 的信息。

本文由 GCTT 原創編譯,Go語言中文網 榮譽推出

本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻么?歡迎加入 GCTT!

翻譯工作和譯文發表僅用于學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯系我們。

歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在正文中標注并保留原文/譯文鏈接和作者/譯者等信息。

文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽

有疑問加站長微信聯系(非本文作者))

總結

以上是生活随笔為你收集整理的mysql 变量生命周期_Go: 延长变量的生命周期的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。