go / expert
Snippet
Ressourcen-Lebenszyklus-Schutz durch runtime.KeepAlive
Bei der Kombination von Finalizern (`runtime.SetFinalizer`) mit nativen Handles (wie Dateideskriptoren oder C-Pointern) kann der Garbage Collector eine Struktur mitten im Methodenaufruf aufräumen, wenn deren Hauptreferenz verfällt. `runtime.KeepAlive` garantiert explizit, dass das Objekt bis zu diesem Ausführungspunkt nicht vom GC erfasst wird.
snippet.go
go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package mainimport ("fmt""runtime""syscall")type FileDescriptorHolder struct {fd int}func NewHolder(fd int) *FileDescriptorHolder {h := &FileDescriptorHolder{fd: fd}runtime.SetFinalizer(h, func(obj *FileDescriptorHolder) {syscall.Close(obj.fd)})return h}func (h *FileDescriptorHolder) Read(b []byte) (int, error) {// If GC runs right here, 'h' could be collected before syscall completes!n, err := syscall.Read(h.fd, b)// Expressly mark 'h' reachable until after the system call finishesruntime.KeepAlive(h)return n, err}func main() {holder := NewHolder(0)buf := make([]byte, 16)_, _ = holder.Read(buf)fmt.Println("Read finished safely")}
Erklärung
1
runtime.SetFinalizer(h, func(obj *FileDescriptorHolder) {
Registriert einen automatischen Bereinigungs-Hook, sobald der Garbage Collector feststellt, dass das Objekt unerreichbar ist.
2
runtime.KeepAlive(h)
Stellt sicher, dass der Compiler und GC 'h' während der Ausführung des Systemaufrufs als erreichbar behandeln.