1 // run 2 3 // Copyright 2015 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 tiny allocations with finalizers are correctly profiled. 8 // Previously profile special records could have been processed prematurely 9 // (while the object is still live). 10 11 package main 12 13 import ( 14 "runtime" 15 "time" 16 "unsafe" 17 ) 18 19 func main() { 20 runtime.MemProfileRate = 1 21 // Allocate 1M 4-byte objects and set a finalizer for every third object. 22 // Assuming that tiny block size is 16, some objects get finalizers setup 23 // only for middle bytes. The finalizer resurrects that object. 24 // As the result, all allocated memory must stay alive. 25 const ( 26 N = 1 << 20 27 tinyBlockSize = 16 // runtime._TinySize 28 ) 29 hold := make([]*int32, 0, N) 30 for i := 0; i < N; i++ { 31 x := new(int32) 32 if i%3 == 0 { 33 runtime.SetFinalizer(x, func(p *int32) { 34 hold = append(hold, p) 35 }) 36 } 37 } 38 // Finalize as much as possible. 39 // Note: the sleep only increases probility of bug detection, 40 // it cannot lead to false failure. 41 for i := 0; i < 5; i++ { 42 runtime.GC() 43 time.Sleep(10 * time.Millisecond) 44 } 45 // Read memory profile. 46 var prof []runtime.MemProfileRecord 47 for { 48 if n, ok := runtime.MemProfile(prof, false); ok { 49 prof = prof[:n] 50 break 51 } else { 52 prof = make([]runtime.MemProfileRecord, n+10) 53 } 54 } 55 // See how much memory in tiny objects is profiled. 56 var totalBytes int64 57 for _, p := range prof { 58 bytes := p.AllocBytes - p.FreeBytes 59 nobj := p.AllocObjects - p.FreeObjects 60 size := bytes / nobj 61 if size == tinyBlockSize { 62 totalBytes += bytes 63 } 64 } 65 // 2*tinyBlockSize slack is for any boundary effects. 66 if want := N*int64(unsafe.Sizeof(int32(0))) - 2*tinyBlockSize; totalBytes < want { 67 println("got", totalBytes, "want >=", want) 68 panic("some of the tiny objects are not profiled") 69 } 70 // Just to keep hold alive. 71 if len(hold) != 0 && hold[0] == nil { 72 panic("bad") 73 } 74 } 75