Know when GC runs from inside your golang code

Overview

gcnotifier

gcnotifier provides a way to receive notifications after every run of the garbage collector (GC). Knowing when GC runs is useful to instruct your code to free additional memory resources that it may be using.

GoDoc GoCover

Why?

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, 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" by your code.

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.

How to use it

The simplest use of this library is as follows:

gcn := gcnotifier.New()
for range gcn.AfterGC() {
  // this code will be executed after every GC cycle
}

As written, the loop above will never terminate, so it is mostly useful if you have global caches that persist for the whole duration of the process.

If you want to ensure the loop terminates (e.g. because you only need the notifications for the lifetime of a different object) you can call the Close() method:

gcn := gcnotifier.New()
go func() {
  for range gcn.AfterGC() {
    // this code will be executed after every GC cycle
    // until Close() is called
  }
}()

// later, or elsewhere in your code
gcn.Close() // the loop above will terminate some time after this call

Note that if a loop iteration takes longer than the interval between two GC cycles it is possible that one notification will be dropped. Followup notifications will be still received correctly.

For a more complex example of how to use it have a look at Example() in gcnotifier_test.go.

For details have a look at the documentation.

How it works

gcnotifier uses finalizers to know when a GC run has completed.

Finalizers are run when the garbage collector finds an unreachable block with an associated finalizer.

The SetFinalizer documentation notes that there is no guarantee that finalizers will run before a program exits. This doesn't mean, as sometimes incorrectly understood, that finalizers are not guaranteed to run at all, it just means that they are not guaranteed to run because GC itself is not guaranteed to run in certain situations: e.g. when the runtime is shutting down. Finalizers can also not run for other reasons (e.g. zero-sized or package-level objects) but they don't apply to gcnotifier because care was taken in the implementation to avoid them.

The only other case in which a notification will not be sent by gcnotifier is if your code hasn't consumed a previously-sent notification. In all other cases if a GC cycle completes your code will receive a notification.

The test in gcnotifier_test.go generates garbage in a loop and makes sure that we receive exactly one notification for each of the first 500 GC runs. In my testing I haven't found a way yet to make gcnotifier fail to notify of a GC run short of shutting down the process or failing to receive the notification. If you manage to make it fail in any other way please file a GitHub issue.

License

MIT

Author

Carlo Alberto Ferraris (@cafxx)

You might also like...
a tool for code clone detection

dupl dupl is a tool written in Go for finding code clones. So far it can find clones only in the Go source files. The method uses suffix tree for seri

[mirror] This is a linter for Go source code.

Golint is a linter for Go source code. Installation Golint requires a supported release of Go. go get -u golang.org/x/lint/golint To find out where g

Run linters from Go code -

Lint - run linters from Go Lint makes it easy to run linters from Go code. This allows lint checks to be part of a regular go build + go test workflow

depth is tool to retrieve and visualize Go source code dependency trees.

depth is tool to retrieve and visualize Go source code dependency trees. Install Download the appropriate binary for your platform from the Rele

A reference for the Go community that covers the fundamentals of writing clean code and discusses concrete refactoring examples specific to Go.

A reference for the Go community that covers the fundamentals of writing clean code and discusses concrete refactoring examples specific to Go.

A static code analyzer for annotated TODO comments
A static code analyzer for annotated TODO comments

todocheck todocheck is a static code analyzer for annotated TODO comments. It let's you create actionable TODOs by annotating them with issues from an

A little fast cloc(Count Lines Of Code)

gocloc A little fast cloc(Count Lines Of Code), written in Go. Inspired by tokei. Installation $ go get -u github.com/hhatto/gocloc/cmd/gocloc Usage

a Go code to detect leaks in JS files via regex patterns

a Go code to detect leaks in JS files via regex patterns

Refactoring and code transformation tool for Go.

gopatch is a tool to match and transform Go code. It is meant to aid in refactoring and restyling.

Comments
  • Doesn't always work

    Doesn't always work

    import "runtime/debug"
    go func() {
    		debug.SetGCPercent(-1)
    		go func() {
    			ticker := time.NewTicker(30 * time.Second)
    			for {
    				select {
    				case <-ticker.C:
    					runtime.GC()
    				}
    			}
    		}()
    
    		gcn := gcnotifier.New()
    		for range gcn.AfterGC() {
    			fmt.Println("Garbage Collected") // Not always detected
    		}
    	}()
    

    It doesn't always work even when I have a finalizer for an object that informs me that GC has actually run.

    opened by pjebs 1
Releases(v0.1.0)
Owner
Carlo Alberto Ferraris
Carlo Alberto Ferraris
A Golang tool that does static analysis, unit testing, code review and generate code quality report.

goreporter A Golang tool that does static analysis, unit testing, code review and generate code quality report. This is a tool that concurrently runs

360 Enterprise Security Group, Endpoint Security, inc. 3k Jan 8, 2023
The most opinionated Go source code linter for code audit.

go-critic Highly extensible Go source code linter providing checks currently missing from other linters. There is never too much static code analysis.

null 1.5k Jan 6, 2023
🐶 Automated code review tool integrated with any code analysis tools regardless of programming language

reviewdog - A code review dog who keeps your codebase healthy. reviewdog provides a way to post review comments to code hosting service, such as GitHu

reviewdog 5.9k Jan 2, 2023
Sloc, Cloc and Code: scc is a very fast accurate code counter with complexity calculations and COCOMO estimates written in pure Go

Sloc Cloc and Code (scc) A tool similar to cloc, sloccount and tokei. For counting physical the lines of code, blank lines, comment lines, and physica

Ben Boyter 4.1k Jan 4, 2023
🐶 Automated code review tool integrated with any code analysis tools regardless of programming language

reviewdog - A code review dog who keeps your codebase healthy. reviewdog provides a way to post review comments to code hosting service, such as GitHu

reviewdog 5.9k Jan 7, 2023
Tool to populate your code with traceable and secure error codes

Essential part of any project, especially customer facing is proper and secure error handling. When error happens and customer reports it, it would be nice to know the context of the error and where it exactly occured.

vs 51 Sep 28, 2022
🔒🌍 Security scanner for your Terraform code

????tfsec uses static analysis of your terraform templates to spot potential security issues.

tfsec 5.5k Dec 30, 2022
Detect non-inclusive language in your source code.

Detect non-inclusive language in your source code. I stay woke - Erykah Badu Creating an inclusive work environment is imperative to a healthy, suppor

woke 361 Dec 25, 2022
Manage your repository's TODOs, tickets and checklists as config in your codebase.

tickgit ??️ tickgit is a tool to help you manage latent work in a codebase. Use the tickgit command to view pending tasks, progress reports, completio

Augmentable 292 Dec 30, 2022
a simple golang SSA viewer tool use for code analysis or make a linter

ssaviewer A simple golang SSA viewer tool use for code analysis or make a linter ssa.html generate code modify from src/cmd/compile/internal/ssa/html.

null 7 May 17, 2022