-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
runtime: support partial object collection in GC #9618
Comments
You don't mention the version of Go, the operating system, or the architecture. Also, was this was discussed first on golang-nuts@, and did the community agree there's a problem and that you're interrupting the numbers correctly? |
When you do make([].., n) and n is constant, the compiler allocates that storage on the stack. It then stores a reference to that storage in the slice. When the slice becomes dead, the compiler does not realize that the underlying stack storage is also dead. This doesn't come up very often in real programs, only because the size is seldom constant. And there are easy workarounds, the simplest being use 0 for the size and append. I'll leave this open for now, but I don't expect anyone to work on it anytime soon. |
@randall77 I do not quite understand the workaround. I think it only solves a one of the two problems this issue reveals. I think a bigger problem is that only if there is no reference to the whole slice, the reference in the slice will be deallocated. If we continue reference only one element in the previous large slice, the memory will not be deallocated. package main
import (
"log"
"runtime"
"time"
)
func bigBytes() []byte {
// 0.1 MB
return make([]byte, 100*1000)
}
func main() {
var mem runtime.MemStats
runtime.ReadMemStats(&mem)
log.Println(mem.Alloc)
log.Println(mem.TotalAlloc)
log.Println(mem.HeapAlloc)
log.Println(mem.HeapSys)
// alloc 100M
ss := make([][]byte, 0)
for i := 0; i < 1000; i++ {
ss = append(ss, bigBytes())
}
// we do expect a deallocation after this point.
ss = ss[:1]
for {
// keep a reference, but should not affect the deallocation
ss[0] = nil
runtime.GC()
time.Sleep(time.Second)
log.Println("after 1s")
runtime.ReadMemStats(&mem)
log.Println(mem.Alloc/1000/1000, "MB")
log.Println(mem.TotalAlloc/1000/1000, "MB")
log.Println(mem.HeapAlloc/1000/1000, "MB")
log.Println(mem.HeapSys/1000/1000, "MB")
}
} output from play.golang.org
|
The GC doesn't support partial object collection yet, so even if you're And transitively, all objects pointed from the unreferenced section of the Partial object collection is tough problem. Is there any existing GC system |
This is not accurate. It is referencing the first byte, not last, of an already unreferenced large object. I think this is a very common case in real world go program that people would shrink the slice without explicitly set the dereferenced part to nil. I agree that Thanks! |
On Fri, Jan 16, 2015 at 8:07 PM, Xiang Li notifications@github.com wrote:
Now that I looked closely with your example, I realized that in your |
Of course you could write s[:1:1] and hope that the trailing portion of the slice would be collected, but that would not happen. And the bookkeeping required to make it happens sounds complex and probably not worth it. If you need the space back, copy the slice. |
@ianlancetaylor But anyway, the user can handle this stuff themselves without adding extra complexity into the go runtime. Thanks! |
It recycles well here (http://play.golang.org/p/qaQaETyZvQ), which appends 1000 elements and not use the slice anymore.
But it doesn't recycle the slice if I make a 1000-element slice first and not use it anymore. (http://play.golang.org/p/CQXs3Rpjae)
If I set some elements in the slice to nil, they can be recycled then. (http://play.golang.org/p/qvYLLZPY74)
I think it should be recycled in all these cases.
The text was updated successfully, but these errors were encountered: