偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Go 1.24 中的弱指針包 weak 使用

開發(fā) 后端
簡而言之,弱指針不會增加對象的引用計數(shù)。當(dāng)一個對象只被弱指針引用時,垃圾回收器就可以釋放它。因此,在嘗試使用弱指針的值之前,應(yīng)檢查它是否為 nil。

在 Go 語言中,“弱指針”指的是不會阻止垃圾回收器(GC)回收目標(biāo)對象的引用。

當(dāng)一個對象只剩弱指針指向它,而沒有任何強(qiáng)引用時,GC 仍會把該對象當(dāng)作不可達(dá)對象并回收;隨后,所有指向它的弱指針會自動變?yōu)?nbsp;nil。

簡而言之,弱指針不會增加對象的引用計數(shù)。當(dāng)一個對象只被弱指針引用時,垃圾回收器就可以釋放它。因此,在嘗試使用弱指針的值之前,應(yīng)檢查它是否為 nil。

Go 1.24 中的 weak 包

Go 1.24 新增 weak 包,提供了創(chuàng)建和使用弱指針的簡潔 API。

import "weak"

type MyStruct struct {
    Data string
}

func main() {
    obj := &MyStruct{Data: "example"}
    wp := weak.Make(obj) // 創(chuàng)建弱指針
    val := wp.Value()    // 獲取強(qiáng)引用或 nil
    if val != nil {
        fmt.Println(val.Data)
    } else {
        fmt.Println("對象已被垃圾回收")
    }
}

在以上示例中,weak.Make(obj) 創(chuàng)建了指向 obj 的弱指針。調(diào)用 wp.Value() 時,如果對象仍存活則返回強(qiáng)引用,否則返回 nil。

測試弱指針:

import (
    "fmt"
    "runtime"
    "weak"
)

type MyStruct struct {
    Data string
}

func main() {
    obj := &MyStruct{Data: "test"}
    wp := weak.Make(obj)
    obj = nil // 移除強(qiáng)引用
    runtime.GC()
    if wp.Value() == nil {
        fmt.Println("對象已被垃圾回收")
    } else {
        fmt.Println("對象仍然存活")
    }
}

通過將強(qiáng)引用 obj 置為 nil 并主動觸發(fā) GC,可觀察到弱指針在對象被回收后返回 nil 的行為。

弱指針”與“強(qiáng)引用”的區(qū)別

特性

強(qiáng)引用 (*T)

弱引用 (weak.Pointer[T])

影響 GC

會保持對象存活

不會保持對象存活

空值

nil

nil

(目標(biāo)被回收或從未賦值)

訪問方式

直接解引用

先調(diào)用 Value()

示例 1: 弱指針做臨時緩存

使用弱指針的一個典型場景是在緩存中存儲條目,同時不阻止它們被 GC 回收。

package main

import (
    "fmt"
    "runtime"
    "sync"
    "weak"
)

type User struct {
    Name string
}

var cache sync.Map // map[int]weak.Pointer[*User]

func GetUser(id int) *User {
    // ① 先從緩存里取
    if wp, ok := cache.Load(id); ok {
        if u := wp.(weak.Pointer[User]).Value(); u != nil {
            fmt.Println("cache hit")
            return u
        }
    }

    // ② 真正加載(這里直接構(gòu)造)
    u := &User{Name: fmt.Sprintf("user-%d", id)}
    cache.Store(id, weak.Make(u))
    fmt.Println("load from DB")
    return u
}

func main() {
    u := GetUser(1) // load from DB
    fmt.Println(u.Name)

    runtime.GC() // 即使立刻 GC,因 main 持有強(qiáng)引用,User 仍在

    u = nil      // 釋放最后一個強(qiáng)引用
    runtime.GC() // 觸發(fā) GC,User 可能被回收

    _ = GetUser(1) // 如被回收,會再次 load from DB
}

在該緩存實現(xiàn)中,條目以弱指針形式存儲。如果對象沒有其他強(qiáng)引用,GC 可以將其回收;下次調(diào)用 GetUser 時,數(shù)據(jù)會被重新加載。

運(yùn)行上述代碼,輸出如下:

$ go run cache.go 
load from DB
user-1
load from DB

為什么要使用弱指針?

常見場景包括:

  • 緩存:在不強(qiáng)制對象常駐內(nèi)存的前提下存儲它們,如果其他地方不再使用,對象就能被回收;
  • 觀察者模式:保存對觀察者的引用,同時不阻止它們被 GC 回收;
  • 規(guī)范化(Canonicalization):確保同一對象只有一個實例,并且在不再使用時可被回收;
  • 依賴關(guān)系圖:在樹或圖等結(jié)構(gòu)中避免形成引用環(huán)。

弱指針使用注意事項

  • 隨時檢查 nil:對象可能在任意 GC 周期后被回收,Value() 結(jié)果不可緩存。
  • 避免循環(huán)依賴:不要讓弱指針中的對象重新持有創(chuàng)建它的容器,否則仍會形成強(qiáng)引用鏈。
  • 性能權(quán)衡:訪問弱指針需要額外調(diào)用,且頻繁從 nil 狀態(tài)恢復(fù)對象會導(dǎo)致抖動。

示例 2:強(qiáng)指針的普通使用

package main  

import (  
 "fmt"  
 "runtime"  
)  

type Session struct {  
 ID string  
}  

func main() {  
 s := new(Session) // 與 &Session{} 等價  
 s.ID = "abc123"  

 fmt.Println("strong ref alive:", s.ID)  

 s = nil           // 取消最后一個強(qiáng)引用  
 runtime.GC()      // 嘗試觸發(fā) GC(僅演示,實際時機(jī)由運(yùn)行時決定)  

 fmt.Println("done")  
}

這里的 s 就是強(qiáng)指針,只要它仍然可達(dá),Session 對象就絕不會被 GC 回收。

強(qiáng)指針指向的對象何時被 GC?

(1) 可達(dá)性判定:Go 使用標(biāo)記-清除式 GC。一次 GC 周期開始時,運(yùn)行時會從根對象(棧、全局變量、當(dāng)前寄存器等)向外遍歷所有強(qiáng)引用。

  • 能通過強(qiáng)引用鏈到達(dá)的對象稱為可達(dá) (reachable),一定存活;
  • 其余對象被標(biāo)記為不可達(dá) (unreachable),在清掃階段釋放。

(2) 不存在“引用計數(shù)”:只有“是否從根可達(dá)”這一條件;變量數(shù)目多少、值是否相等都不影響回收;

(3) 時間點不確定:GC 周期由調(diào)度器自動觸發(fā),開發(fā)者只能調(diào)用 runtime.GC() 進(jìn)行“建議”式觸發(fā),不能保證立即回收;

(4) 變量本身也會被 GC:若強(qiáng)指針變量 s 位于堆上且其所在結(jié)構(gòu)不再可達(dá),那么 s 本身也會被 GC;棧變量則隨函數(shù)返回被回收。

總結(jié)一句:強(qiáng)指針保證可達(dá)對象在任意 GC 周期都處于“存活集合”中;一旦最后的強(qiáng)引用鏈斷開,對象就會在下一個 GC 周期被自動釋放。

責(zé)任編輯:趙寧寧 來源: 孔令飛
相關(guān)推薦

2024-10-09 08:54:31

2025-07-29 10:00:00

指針開發(fā)Go

2025-09-16 08:49:13

2023-10-26 11:19:21

指針Go

2025-05-06 08:00:35

2015-07-08 16:28:23

weak生命周期

2015-03-16 10:33:14

Swift指針

2015-01-21 16:25:29

Swift指針

2024-09-03 08:49:01

2025-05-07 08:55:14

GoMap存儲

2021-09-27 22:49:13

GoC 指針

2021-04-13 07:58:42

Go語言函數(shù)

2025-03-07 09:12:28

2021-10-26 13:18:52

Go底層函數(shù)

2022-01-10 13:01:32

指針Struct內(nèi)存

2025-01-06 09:18:04

2022-08-08 08:31:55

Go 語言閉包匿名函數(shù)

2022-08-08 06:50:06

Go語言閉包

2025-05-26 08:15:00

Go開發(fā)指針

2025-05-26 10:10:00

Go開發(fā)testing
點贊
收藏

51CTO技術(shù)棧公眾號