mirror of
				https://github.com/golang/go.git
				synced 2025-10-31 16:50:58 +00:00 
			
		
		
		
	
		
			
	
	
		
			75 lines
		
	
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			75 lines
		
	
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|   | // run | ||
|  | 
 | ||
|  | // Copyright 2015 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 tiny allocations with finalizers are correctly profiled. | ||
|  | // Previously profile special records could have been processed prematurely | ||
|  | // (while the object is still live). | ||
|  | 
 | ||
|  | package main | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"runtime" | ||
|  | 	"time" | ||
|  | 	"unsafe" | ||
|  | ) | ||
|  | 
 | ||
|  | func main() { | ||
|  | 	runtime.MemProfileRate = 1 | ||
|  | 	// Allocate 1M 4-byte objects and set a finalizer for every third object. | ||
|  | 	// Assuming that tiny block size is 16, some objects get finalizers setup | ||
|  | 	// only for middle bytes. The finalizer resurrects that object. | ||
|  | 	// As the result, all allocated memory must stay alive. | ||
|  | 	const ( | ||
|  | 		N = 1 << 20 | ||
|  | 		tinyBlockSize = 16 // runtime._TinySize | ||
|  | 	) | ||
|  | 	hold := make([]*int32, 0, N) | ||
|  | 	for i := 0; i < N; i++ { | ||
|  | 		x := new(int32) | ||
|  | 		if i%3 == 0 { | ||
|  | 			runtime.SetFinalizer(x, func(p *int32) { | ||
|  | 				hold = append(hold, p) | ||
|  | 			}) | ||
|  | 		} | ||
|  | 	} | ||
|  | 	// Finalize as much as possible. | ||
|  | 	// Note: the sleep only increases probility of bug detection, | ||
|  | 	// it cannot lead to false failure. | ||
|  | 	for i := 0; i < 5; i++ { | ||
|  | 		runtime.GC() | ||
|  | 		time.Sleep(10 * time.Millisecond) | ||
|  | 	} | ||
|  | 	// Read memory profile. | ||
|  | 	var prof []runtime.MemProfileRecord | ||
|  | 	for { | ||
|  | 		if n, ok := runtime.MemProfile(prof, false); ok { | ||
|  | 			prof = prof[:n] | ||
|  | 			break | ||
|  | 		} else { | ||
|  | 			prof = make([]runtime.MemProfileRecord, n+10) | ||
|  | 		} | ||
|  | 	} | ||
|  | 	// See how much memory in tiny objects is profiled. | ||
|  | 	var totalBytes int64 | ||
|  | 	for _, p := range prof { | ||
|  | 		bytes := p.AllocBytes - p.FreeBytes | ||
|  | 		nobj := p.AllocObjects - p.FreeObjects | ||
|  | 		size := bytes / nobj | ||
|  | 		if size == tinyBlockSize { | ||
|  | 			totalBytes += bytes | ||
|  | 		} | ||
|  | 	} | ||
|  | 	// 2*tinyBlockSize slack is for any boundary effects. | ||
|  | 	if want := N*int64(unsafe.Sizeof(int32(0))) - 2*tinyBlockSize; totalBytes < want { | ||
|  | 		println("got", totalBytes, "want >=", want) | ||
|  | 		panic("some of the tiny objects are not profiled") | ||
|  | 	} | ||
|  | 	// Just to keep hold alive. | ||
|  | 	if len(hold) != 0 && hold[0] == nil { | ||
|  | 		panic("bad") | ||
|  | 	} | ||
|  | } |