summaryrefslogtreecommitdiff
path: root/libgo/go/runtime/testdata/testprog/gc.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/runtime/testdata/testprog/gc.go')
-rw-r--r--libgo/go/runtime/testdata/testprog/gc.go52
1 files changed, 46 insertions, 6 deletions
diff --git a/libgo/go/runtime/testdata/testprog/gc.go b/libgo/go/runtime/testdata/testprog/gc.go
index cc16413ef5c..74732cd9f4b 100644
--- a/libgo/go/runtime/testdata/testprog/gc.go
+++ b/libgo/go/runtime/testdata/testprog/gc.go
@@ -11,6 +11,7 @@ import (
"runtime/debug"
"sync/atomic"
"time"
+ "unsafe"
)
func init() {
@@ -19,6 +20,7 @@ func init() {
register("GCSys", GCSys)
register("GCPhys", GCPhys)
register("DeferLiveness", DeferLiveness)
+ register("GCZombie", GCZombie)
}
func GCSys() {
@@ -150,16 +152,20 @@ func GCPhys() {
// The page cache could hide 64 8-KiB pages from the scavenger today.
maxPageCache = (8 << 10) * 64
+
+ // Reduce GOMAXPROCS down to 4 if it's greater. We need to bound the amount
+ // of memory held in the page cache because the scavenger can't reach it.
+ // The page cache will hold at most maxPageCache of memory per-P, so this
+ // bounds the amount of memory hidden from the scavenger to 4*maxPageCache
+ // at most.
+ maxProcs = 4
)
// Set GOGC so that this test operates under consistent assumptions.
debug.SetGCPercent(100)
- // Reduce GOMAXPROCS down to 4 if it's greater. We need to bound the amount
- // of memory held in the page cache because the scavenger can't reach it.
- // The page cache will hold at most maxPageCache of memory per-P, so this
- // bounds the amount of memory hidden from the scavenger to 4*maxPageCache.
procs := runtime.GOMAXPROCS(-1)
- if procs > 4 {
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+ if procs > maxProcs {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
+ procs = runtime.GOMAXPROCS(-1)
}
// Save objects which we want to survive, and condemn objects which we don't.
// Note that we condemn objects in this way and release them all at once in
@@ -260,3 +266,37 @@ func DeferLiveness() {
func escape(x interface{}) { sink2 = x; sink2 = nil }
var sink2 interface{}
+
+// Test zombie object detection and reporting.
+func GCZombie() {
+ // Allocate several objects of unusual size (so free slots are
+ // unlikely to all be re-allocated by the runtime).
+ const size = 190
+ const count = 8192 / size
+ keep := make([]*byte, 0, (count+1)/2)
+ free := make([]uintptr, 0, (count+1)/2)
+ zombies := make([]*byte, 0, len(free))
+ for i := 0; i < count; i++ {
+ obj := make([]byte, size)
+ p := &obj[0]
+ if i%2 == 0 {
+ keep = append(keep, p)
+ } else {
+ free = append(free, uintptr(unsafe.Pointer(p)))
+ }
+ }
+
+ // Free the unreferenced objects.
+ runtime.GC()
+
+ // Bring the free objects back to life.
+ for _, p := range free {
+ zombies = append(zombies, (*byte)(unsafe.Pointer(p)))
+ }
+
+ // GC should detect the zombie objects.
+ runtime.GC()
+ println("failed")
+ runtime.KeepAlive(keep)
+ runtime.KeepAlive(zombies)
+}