SeriesPart 5 of 9 // Go 1.24
GoWriting
Feb 8, 2025
3 min read

Improved Finalization in Go 1.24: Introducing runtime.AddCleanup

Go 1.24 introduces a significant improvement in how Go handles finalization and resource clean-up with the new runtime.AddCleanup function…

Go 1.24 introduces a significant improvement in how Go handles finalization and resource clean-up with the new runtime.AddCleanup function…

Improved Finalization in Go 1.24: Introducing runtime.AddCleanup

Go 1.24 introduces a significant improvement in how Go handles finalization and resource clean-up with the new runtime.AddCleanup function. This new mechanism provides a more efficient and flexible way to perform clean-up actions compared to the traditional runtime.SetFinalizer.

Why runtime.AddCleanup?

Finalizers in Go are used to run clean-up code when an object becomes unreachable, helping to release system resources such as file handles and network connections. However, runtime.SetFinalizer has several limitations:

  • Unpredictable Execution: The execution of finalizers depends on garbage collection, which is non-deterministic.
  • Risk of Memory Leaks: Objects with finalizers may be kept alive longer than necessary.
  • Difficulty Handling Cyclic References: When objects reference each other, finalization may not trigger as expected.

To address these issues, Go 1.24 introduces runtime.AddCleanup, offering a more structured and predictable approach to resource clean-up.

Using runtime.AddCleanup

Basic Example

Here’s how runtime.AddCleanup can be used to register clean-up functions:

package main
 
import (
  "database/sql"
  "fmt"
  "runtime"
 
  "github.com/DATA-DOG/go-sqlmock"
)
 
type Resource struct {
  db *sql.DB
}
 
func NewResource() *Resource {
  db, _, _ := sqlmock.New()
  res := &Resource{db: db}
 
  runtime.AddCleanup(res, func(db *sql.DB) {
    fmt.Println("Closing DB connection")
    _ = db.Close()
  }, res.db)
 
  return res
}
 
func main() {
  res := NewResource()
  _ = res
  res = nil
  runtime.GC()
}

Key Advantages

  • Multiple Clean-up Functions: Unlike runtime.SetFinalizer, multiple clean-up functions can be attached to a single object.
  • Handles Cyclic References: Works better in cases where objects form reference cycles.
  • Does Not Delay Object Deallocation: Clean-up is handled more efficiently without prolonging the object’s lifetime unnecessarily.

Comparison with runtime.SetFinalizer

Featureruntime.SetFinalizerruntime.AddCleanup
Execution TimingNon-deterministic, tied to GC More predictableMultiple Cleanups Not supported Supported
Handles CyclesNoYes
Memory EfficiencyCan delay object collectionMore efficient

Use Cases for runtime.AddCleanup

  • Managing File and Network Handles: Ensuring files and connections are closed properly.
  • Preventing Memory Leaks: Efficient clean-up of in-memory caches and temporary objects.
  • More Reliable Finalization: Providing a structured approach to cleaning up resources.

Conclusion

The introduction of runtime.AddCleanup in Go 1.24 enhances the way finalization works, addressing key limitations of runtime.SetFinalizer. It provides a more predictable, flexible, and efficient way to manage resource clean-up.

Stay tuned for the next post, where we explore the new weak package and how it enables weak pointers for more memory-efficient applications.

By Ajitem Sahasrabuddhe on February 8, 2025.

Series contents