Documentation
¶
Overview ¶
Package gcnotifier provides a way to receive notifications after every garbage collection (GC) cycle. This can be useful, in long-running programs, to instruct your code to free additional memory resources that you may be using.
A common use case for this is when you have custom data structures (e.g. buffers, caches, rings, trees, pools, ...): instead of setting a maximum size to your data structure you can leave it unbounded and then drop all (or some) of the allocated-but-unused slots after every GC run (e.g. sync.Pool drops all allocated-but-unused objects in the pool during GC).
To minimize the load on the GC the code that runs after receiving the notification should try to avoid allocations as much as possible, or at the very least make sure that the amount of new memory allocated is significantly smaller than the amount of memory that has been "freed" in response to the notification.
GCNotifier guarantees to send a notification after every GC cycle completes. Note that the Go runtime does not guarantee that the GC will run: specifically there is no guarantee that a GC will run before the program terminates.
Example ¶
Example implements a simple time-based buffering io.Writer: data sent over dataCh is buffered for up to 100ms, then flushed out in a single call to out.Write and the buffer is reused. If GC runs, the buffer is flushed and then discarded so that it can be collected during the next GC run. The example is necessarily simplistic, a real implementation would be more refined (e.g. on GC flush or resize the buffer based on a threshold, perform asynchronous flushes, properly signal completions and propagate errors, adaptively preallocate the buffer based on the previous capacity, etc.)
dataCh := make(chan []byte) doneCh := make(chan struct{}) out := ioutil.Discard go func() { var buf []byte var tick <-chan time.Time gcn := New() for { select { case data := <-dataCh: if tick == nil { tick = time.After(100 * time.Millisecond) } // received data to write to the buffer buf = append(buf, data...) case <-tick: // time to flush the buffer (but reuse it for the next writes) if len(buf) > 0 { out.Write(buf) buf = buf[:0] } tick = nil case <-gcn.AfterGC(): // GC just ran: flush and then drop the buffer if len(buf) > 0 { out.Write(buf) } buf = nil tick = nil case <-doneCh: // close the writer: flush the buffer and return if len(buf) > 0 { out.Write(buf) } return } } }() for i := 0; i < 1<<20; i++ { dataCh <- make([]byte, 1024) } doneCh <- struct{}{}
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type GCNotifier ¶
type GCNotifier struct {
// contains filtered or unexported fields
}
GCNotifier allows your code to control and receive notifications every time the garbage collector runs.
func (*GCNotifier) AfterGC ¶
func (n *GCNotifier) AfterGC() <-chan struct{}
AfterGC returns the channel that will receive a notification after every GC run. No further notifications will be sent until the previous notification has been consumed. To stop notifications immediately call the Close() method. Otherwise notifications will continue until the GCNotifier object itself is garbage collected. Note that the channel returned by AfterGC will be closed only when GCNotifier is garbage collected. The channel is unique to a single GCNotifier object: use dedicated GCNotifiers if you need to listen for GC notifications in multiple receivers at the same time.
func (*GCNotifier) Close ¶
func (n *GCNotifier) Close()
Close will stop and release all resources associated with the GCNotifier. It is not required to call Close explicitly: when the GCNotifier object is garbage collected Close is called implicitly. If you don't call Close explicitly make sure not to accidently maintain the GCNotifier object alive.