Skip to content

Reference counting with atomic operations

Reference counting with atomic operations is a memory management technique where a shared object's lifecycle is managed by a counter, manipulated using atomic hardware instructions to ensure thread safety without heavy locking.^[600-developer-big-data-netty-netty-rotate.md]

In concurrent programming, Reference counting tracks the number of active references to a resource (such as a network buffer). When the count drops to zero, the resource is deallocated.^[600-developer-big-data-netty-netty-rotate.md]

Implementation details

The implementation relies on a volatile integer field to store the reference count (refCnt).^[600-developer-big-data-netty-netty-rotate.md] To manage this counter efficiently, the logic typically utilizes an AtomicIntegerFieldUpdater.^[600-developer-big-data-netty-netty-rotate.md] This updater allows performant atomic operations on the standard volatile field, avoiding the memory overhead of creating AtomicInteger objects for every instance.^[600-developer-big-data-netty-netty-rotate.md]

Retaining references

Increasing the reference count (often called a "retain" operation) involves a loop that continuously attempts to add an increment to the current value.^[600-developer-big-data-netty-netty-rotate.md]

The core logic for incrementing is:

  1. Read the current count: Fetch the latest refCnt value.^[600-developer-big-data-netty-netty-rotate.md]
  2. Calculate the next count: Add the desired increment to the current value.^[600-developer-big-data-netty-netty-rotate.md]
  3. Validate: Check if nextCnt <= increment.^[600-developer-big-data-netty-netty-rotate.md] If this is true, it indicates that the reference count was either zero (indicating the object is dead and should not be "resurrected") or that an integer overflow has occurred.^[600-developer-big-data-netty-netty-rotate.md]
  4. Atomic Update: Use compareAndSet (CAS) to update the field.^[600-developer-big-data-netty-netty-rotate.md]
    • If the CAS succeeds (the current value in memory matches the refCnt we read), the loop breaks.^[600-developer-big-data-netty-netty-rotate.md]
    • If the CAS fails (another thread modified the count), the loop repeats.^[600-developer-big-data-netty-netty-rotate.md]

Releasing references

Decreasing the reference count ("release") follows a similar optimistic locking pattern.^[600-developer-big-data-netty-netty-rotate.md]

  1. Check bounds: Ensure the current reference count is not less than the decrement amount to prevent underflow.^[600-developer-big-data-netty-netty-rotate.md]
  2. Atomic Update: Use compareAndSet to atomically swap the current count with the decremented value.^[600-developer-big-data-netty-netty-rotate.md]
  3. Deallocate: If the CAS succeeds and the old count matches the decrement (meaning the count has hit zero), the resource is deallocated.^[600-developer-big-data-netty-netty-rotate.md]

This approach ensures that deallocation happens exactly once when the last reference is released.

Sources

^[600-developer-big-data-netty-netty-rotate.md]