mirror of
https://github.com/golang/go
synced 2024-10-02 22:25:08 +00:00
runtime: fix memory leaks due to defers
fn can clearly hold a closure in memory. argp/pc point into stack and so can hold in memory a block that was previously a large stack serment. R=golang-dev, dave, rsc CC=golang-dev https://golang.org/cl/10784043
This commit is contained in:
parent
20498ed772
commit
fd23958f49
|
@ -104,11 +104,15 @@ popdefer(void)
|
|||
static void
|
||||
freedefer(Defer *d)
|
||||
{
|
||||
int32 total;
|
||||
|
||||
if(d->special) {
|
||||
if(d->free)
|
||||
runtime·free(d);
|
||||
} else {
|
||||
runtime·memclr((byte*)d->args, d->siz);
|
||||
// Wipe out any possible pointers in argp/pc/fn/args.
|
||||
total = sizeof(*d) + ROUND(d->siz, sizeof(uintptr)) - sizeof(d->args);
|
||||
runtime·memclr((byte*)d, total);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
59
test/deferfin.go
Normal file
59
test/deferfin.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
// run
|
||||
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Test that defers do not prevent garbage collection.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var sink func()
|
||||
|
||||
func main() {
|
||||
// Does not work on 32-bits due to partially conservative GC.
|
||||
// Try to enable when we have fully precise GC.
|
||||
if runtime.GOARCH != "amd64" {
|
||||
return
|
||||
}
|
||||
N := 10
|
||||
count := int32(N)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(N)
|
||||
for i := 0; i < N; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
v := new(int)
|
||||
f := func() {
|
||||
if *v != 0 {
|
||||
panic("oops")
|
||||
}
|
||||
}
|
||||
if *v != 0 {
|
||||
// let the compiler think f escapes
|
||||
sink = f
|
||||
}
|
||||
runtime.SetFinalizer(v, func(p *int) {
|
||||
atomic.AddInt32(&count, -1)
|
||||
})
|
||||
defer f()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
for i := 0; i < 3; i++ {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
runtime.GC()
|
||||
}
|
||||
if count != 0 {
|
||||
println(count, "out of", N, "finalizer are not called")
|
||||
panic("not all finalizers are called")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in a new issue