I’m curious concerning the present state of rubbish assortment for slices in Go. Is the Go rubbish collector nonetheless unable to gather objects which can be not accessible however are referenced by the underlying array of a slice?
As an example, within the following code, is it doable for the rubbish collector to gather a
at line 5?
a := 1
s := make([]*int, 2)
s[0] = &a
s = s[1:]
// GC at this level
Are there any instruments to detect this? I checked Staticcheck and go vet and it appeared that none of them can detect the problem.
No, you’re really referencing the reminiscence of the underlying array, so GC received’t reclaim this a part of the reminiscence.
You should utilize the features of the runtime bundle to set off and examine the reminiscence utilization in imitation of lively GC.
Thanks. However what I take note of is the a
object, which is referenced by inaccessible parts s[0]
of slice s
.
If I exploit s[0] = nil
earlier than project s = s[1:]
, a
may be reclaimed by GC on the final line, proper? But when a programmer forgets to write down s[0] = nil
and the GC is unable to acknowledge the inaccessible a
and reclaim it, a lot reminiscence might not be reclaimed.
im nonetheless a go noob however from what i perceive utilizing nil
to deference isnt normal follow because the GC is sensible sufficient to deal with such circumstances by itself
I feel you’re oversimplifying and don’t know if you already know concerning the unsafe bundle, which may be much like the offset level of C (that is simply an instance), and easily reclaiming reminiscence will trigger sudden issues.
s -> s[0] -> a
s[1]
// s=s[1:]
s[0] -> a
s -> s[1]
While you use s, you’re really referencing the whole underlying array, and GC doesn’t recycle the reminiscence of the underlying array. On the identical time, as a result of the underlying array references the reminiscence that A factors to, the reminiscence of A is not going to gc.
The reminiscence pointed to by a will solely be freed if there isn’t a reference to the underlying array in your context. It’s not onerous to see why.
As for why GC doesn’t deal with this type of factor for you, I feel you’re placing the cart earlier than the horse: the benefit of use of Golang doesn’t imply it stops you from writing dangerous code at will.
Consciousness of reminiscence allocation is a fundamental high quality for builders (I admit that golang is straightforward to get began with, however I’ve encountered numerous builders who write dangerous code).
Thanks on your detailed reply. I do know the unsafe bundle and its doable impact to GC(I’m not so certain, so I’m asking right here). What about set nil
to s[0]
(manually or semi-automatically) to make a
not referenced by the underlying array of s
? I feel it’s a superb follow if a
may be reclaimed instantly as a substitute of being reclaimed on the identical time of reclaiming underlying array of s
, i.e. shortening the lifespan of a
to its precise lifespan.
Because the above reply mentions, can GC deal with nil
well? Is that true? Is there any supply code or weblog that I can reference? Or someplace else to negate the predicate “GC is sensible sufficient to deal with such circumstances by itself”?
New generic slices
bundle has Delete
perform. It zero/nil out the out of date parts, to allow them to be collected by GC. However on the identical time underline array is not going to change its capability. Thus, the reminiscence already allotted for it is going to keep the identical.
I don’t suppose you perceive what I’m speaking about.
As I stated above, it’s basically as a result of the underlying array of s has a pointer to A, so A can’t be reclaimed by GC reminiscence, which is the only and clearest method to put it. So if the underlying array of s doesn’t have a pointer to A, then A might be reclaimed by the GC reminiscence, be aware that this isn’t a direct assortment, the GC has its personal set of logic.
In the event you don’t set nil and S is used on a regular basis, then A reminiscence won’t ever be reclaimed. (On this be aware, you’ll be able to write a runtime to see the reminiscence footprint of the pattern code, it is likely to be extra intuitive to show a into an extended string)
var m runtime.MemStats
var a string
a = uuid.NewIdn(1024 * 1024)
fmt.Println(len(a)) //len 1024 * 1024
s := make([]*string, 2)
s[0] = &a
for i := 0; i < 10; i++ {
time.Sleep(100 * time.Millisecond)
runtime.ReadMemStats(&m)
fmt.Println(m.Alloc)
runtime.GC()
}
s[0] = nil //Please touch upon this line repeatedly for comparability
s = s[1:] //Please touch upon this line repeatedly for comparability
for i := 0; i < 10; i++ {
time.Sleep(100 * time.Millisecond)
runtime.ReadMemStats(&m)
fmt.Println(m.Alloc)
runtime.GC()
}
fmt.Println(s[0]) //Please touch upon this line repeatedly for comparability
As for automation, no! I repeat, no!
Golang’s GC doesn’t mechanically arrange nil for you, and if it does, it is going to result in a number of different issues, so the very best factor to do is to do nothing and let the builders resolve the issue themselves.