Слабые указатели

Если вы сильный программист, то не читайте дальше

Слабый указатель (пакет weak в Go 1.24+) ссылается на объект, как обычный указатель. Но в отличие от обычного указателя, слабый указатель не способен удержать объект в памяти. Если на объект ссылаются только слабые указатели, сборщик мусора может освободить занимаемую им память.

Предположим, у нас есть тип blob (реализация скрыта для краткости):

// Blob is a large byte slice.
type Blob []byte

И указатель на блоб размером в 1000 КБ:

b := newBlob(1000)

Мы можем создать слабый указатель (weak.Pointer) из обычного с помощью weak.Make. А получить доступ к оригинальному указателю поможет Pointer.Value:

wb := weak.Make(newBlob(1000))
fmt.Println(wb.Value())
// Blob(1000 KB)

Обычный указатель не позволит сборщику мусора освободить занятую объектом память:

b := newBlob(1000)
fmt.Println("before GC =", b)
runtime.GC()
fmt.Println("after GC =", b)
before GC = Blob(1000 KB)
after GC = Blob(1000 KB)

Слабый указатель же разрешает сборщику мусора освободить память:

wb := weak.Make(newBlob(1000))
fmt.Println("before GC =", wb.Value())
runtime.GC()
fmt.Println("after GC =", wb.Value())
before GC = Blob(1000 KB)
after GC = <nil>

Как видите, Pointer.Value возвращает nil, если сборщик мусора уже освободил значение по указателю.

Пр этом нет гарантии, что nil вернется сразу после того, как объект перестал использоваться (или в любое другое время позже). Рантайм сам решает, когда освобождать память, и освобождать ли вообще.

Слабые указатели могут пригодиться для реализации кэша больших объектов. Они гарантируют, что объект не будет оставаться в памяти только потому, что он находится в кэше.

Мы еще поговорим об этом в следующий раз.

★ Подписывайтесь на новые заметки.