github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/test/deferfin.go (about)

     1  // run
     2  
     3  // Copyright 2013 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // Test that defers do not prevent garbage collection.
     8  
     9  package main
    10  
    11  import (
    12  	"runtime"
    13  	"sync"
    14  	"sync/atomic"
    15  	"time"
    16  )
    17  
    18  var sink func()
    19  
    20  func main() {
    21  	// Does not work on 32-bits due to partially conservative GC.
    22  	// Try to enable when we have fully precise GC.
    23  	if runtime.GOARCH != "amd64" {
    24  		return
    25  	}
    26  	// Likewise for gccgo.
    27  	if runtime.Compiler == "gccgo" {
    28  		return
    29  	}
    30  	N := 10
    31  	count := int32(N)
    32  	var wg sync.WaitGroup
    33  	wg.Add(N)
    34  	for i := 0; i < N; i++ {
    35  		go func() {
    36  			defer wg.Done()
    37  			v := new(string)
    38  			f := func() {
    39  				if *v != "" {
    40  					panic("oops")
    41  				}
    42  			}
    43  			if *v != "" {
    44  				// let the compiler think f escapes
    45  				sink = f
    46  			}
    47  			runtime.SetFinalizer(v, func(p *string) {
    48  				atomic.AddInt32(&count, -1)
    49  			})
    50  			defer f()
    51  		}()
    52  	}
    53  	wg.Wait()
    54  	for i := 0; i < 3; i++ {
    55  		time.Sleep(10 * time.Millisecond)
    56  		runtime.GC()
    57  	}
    58  	if count != 0 {
    59  		println(count, "out of", N, "finalizer are not called")
    60  		panic("not all finalizers are called")
    61  	}
    62  }
    63