FAQ
This program shows a memory leak.

I don't think it should leak, unless I'm confused.

Ideas?


package main

import (
"fmt"
"runtime"
"time"
)

type buffer struct {
a int
b []byte
c int
}

func main() {
c := make(chan bool)
const n = 500
for i := 0; i < n; i++ {
go func() {
myc := c
for {
var b buffer
<-myc // pass by here once, then block
forever.
myc = nil

// This buffer should only survive for the
next 2 lines
// and the call to foo. Once the for loop
returns to
// the "var b buffer" line, b.b should be
zero, and the
// GC should have collected it.

b.b = make([]byte, 2 << 20)
foo(b)

// This doesn't even help:

// b.b = nil

}
}()
}
for i := 0; i < n; i ++ {
select {
case c <- true:
default:
}
runtime.GC()
var s runtime.MemStats
runtime.ReadMemStats(&s)
fmt.Printf("alloc (still in use): %d\n", s.Alloc)
fmt.Printf(" sys: %d\n", s.Sys)
fmt.Printf(" num gc: %d\n", s.NumGC)
fmt.Println()
time.Sleep(1 * time.Second)
}
}

func foo(b buffer) {
// nothing

}

Search Discussions

  • Brad Fitzpatrick at Oct 9, 2012 at 12:43 am
    It appears to be an inlining bug.

    It works fine if I compile with -l.

    bradfitz@bradfitzlap:~$ go run -gcflags -l leak.go
    alloc (still in use): 381360
    sys: 4734976
    num gc: 2

    alloc (still in use): 437984
    sys: 4866048
    num gc: 3

    alloc (still in use): 441968
    sys: 8534264
    num gc: 5

    alloc (still in use): 441968
    sys: 8534264
    num gc: 7

    alloc (still in use): 441968
    sys: 8534264
    num gc: 9

    alloc (still in use): 441968
    sys: 8534264
    num gc: 11

    alloc (still in use): 441968
    sys: 8534264
    num gc: 13

    alloc (still in use): 441968
    sys: 8534264
    num gc: 15

    ^Cbradfitz@bradfitzlap:~$ go run leak.go
    alloc (still in use): 385376
    sys: 6174968
    num gc: 2

    alloc (still in use): 442000
    sys: 6306040
    num gc: 3

    alloc (still in use): 2539296
    sys: 8534264
    num gc: 5

    alloc (still in use): 4638752
    sys: 10762488
    num gc: 6

    alloc (still in use): 6738208
    sys: 12990712
    num gc: 7

    alloc (still in use): 8837664
    sys: 15218936
    num gc: 8

    alloc (still in use): 10937120
    sys: 17447160
    num gc: 9

    alloc (still in use): 13036576
    sys: 19675384
    num gc: 10

    alloc (still in use): 15136032
    sys: 21903608
    num gc: 11

    On Mon, Oct 8, 2012 at 5:21 PM, Brad Fitzpatrick wrote:

    This program shows a memory leak.

    I don't think it should leak, unless I'm confused.

    Ideas?


    package main

    import (
    "fmt"
    "runtime"
    "time"
    )

    type buffer struct {
    a int
    b []byte
    c int
    }

    func main() {
    c := make(chan bool)
    const n = 500
    for i := 0; i < n; i++ {
    go func() {
    myc := c
    for {
    var b buffer
    <-myc // pass by here once, then block
    forever.
    myc = nil

    // This buffer should only survive for the
    next 2 lines
    // and the call to foo. Once the for loop
    returns to
    // the "var b buffer" line, b.b should be
    zero, and the
    // GC should have collected it.

    b.b = make([]byte, 2 << 20)
    foo(b)

    // This doesn't even help:

    // b.b = nil

    }
    }()
    }
    for i := 0; i < n; i ++ {
    select {
    case c <- true:
    default:
    }
    runtime.GC()
    var s runtime.MemStats
    runtime.ReadMemStats(&s)
    fmt.Printf("alloc (still in use): %d\n", s.Alloc)
    fmt.Printf(" sys: %d\n", s.Sys)
    fmt.Printf(" num gc: %d\n", s.NumGC)
    fmt.Println()
    time.Sleep(1 * time.Second)
    }
    }

    func foo(b buffer) {
    // nothing

    }
  • Brad Fitzpatrick at Oct 9, 2012 at 12:43 am
    Filed http://code.google.com/p/go/issues/detail?id=4217

    ... now that I'm confident that it's a bug.

    Feel free to move any discussion there.

    On Mon, Oct 8, 2012 at 5:37 PM, Brad Fitzpatrick wrote:

    It appears to be an inlining bug.

    It works fine if I compile with -l.

    bradfitz@bradfitzlap:~$ go run -gcflags -l leak.go
    alloc (still in use): 381360
    sys: 4734976
    num gc: 2

    alloc (still in use): 437984
    sys: 4866048
    num gc: 3

    alloc (still in use): 441968
    sys: 8534264
    num gc: 5

    alloc (still in use): 441968
    sys: 8534264
    num gc: 7

    alloc (still in use): 441968
    sys: 8534264
    num gc: 9

    alloc (still in use): 441968
    sys: 8534264
    num gc: 11

    alloc (still in use): 441968
    sys: 8534264
    num gc: 13

    alloc (still in use): 441968
    sys: 8534264
    num gc: 15

    ^Cbradfitz@bradfitzlap:~$ go run leak.go
    alloc (still in use): 385376
    sys: 6174968
    num gc: 2

    alloc (still in use): 442000
    sys: 6306040
    num gc: 3

    alloc (still in use): 2539296
    sys: 8534264
    num gc: 5

    alloc (still in use): 4638752
    sys: 10762488
    num gc: 6

    alloc (still in use): 6738208
    sys: 12990712
    num gc: 7

    alloc (still in use): 8837664
    sys: 15218936
    num gc: 8

    alloc (still in use): 10937120
    sys: 17447160
    num gc: 9

    alloc (still in use): 13036576
    sys: 19675384
    num gc: 10

    alloc (still in use): 15136032
    sys: 21903608
    num gc: 11

    On Mon, Oct 8, 2012 at 5:21 PM, Brad Fitzpatrick wrote:

    This program shows a memory leak.

    I don't think it should leak, unless I'm confused.

    Ideas?


    package main

    import (
    "fmt"
    "runtime"
    "time"
    )

    type buffer struct {
    a int
    b []byte
    c int
    }

    func main() {
    c := make(chan bool)
    const n = 500
    for i := 0; i < n; i++ {
    go func() {
    myc := c
    for {
    var b buffer
    <-myc // pass by here once, then
    block forever.
    myc = nil

    // This buffer should only survive for
    the next 2 lines
    // and the call to foo. Once the for loop
    returns to
    // the "var b buffer" line, b.b should be
    zero, and the
    // GC should have collected it.

    b.b = make([]byte, 2 << 20)
    foo(b)

    // This doesn't even help:

    // b.b = nil

    }
    }()
    }
    for i := 0; i < n; i ++ {
    select {
    case c <- true:
    default:
    }
    runtime.GC()
    var s runtime.MemStats
    runtime.ReadMemStats(&s)
    fmt.Printf("alloc (still in use): %d\n", s.Alloc)
    fmt.Printf(" sys: %d\n", s.Sys)
    fmt.Printf(" num gc: %d\n", s.NumGC)
    fmt.Println()
    time.Sleep(1 * time.Second)
    }
    }

    func foo(b buffer) {
    // nothing

    }

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-dev @
categoriesgo
postedOct 9, '12 at 12:21a
activeOct 9, '12 at 12:43a
posts3
users1
websitegolang.org

1 user in discussion

Brad Fitzpatrick: 3 posts

People

Translate

site design / logo © 2022 Grokbase