gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/refs/README.md (about)

     1  # Reference Counting
     2  
     3  Go does not offer a reliable way to couple custom resource management with
     4  object lifetime. As a result, we need to manually implement reference counting
     5  for many objects in gVisor to make sure that resources are acquired and released
     6  appropriately. For example, the filesystem has many reference-counted objects
     7  (file descriptions, dentries, inodes, etc.), and it is important that each
     8  object persists while anything holds a reference on it and is destroyed once all
     9  references are dropped.
    10  
    11  We provide a template in `refs_template.go` that can be applied to most objects
    12  in need of reference counting. It contains a simple `Refs` struct that can be
    13  incremented and decremented, and once the reference count reaches zero, a
    14  destructor can be called. Note that there are some objects (e.g. `gofer.dentry`,
    15  `overlay.dentry`) that should not immediately be destroyed upon reaching zero
    16  references; in these cases, this template cannot be applied.
    17  
    18  # Reference Checking
    19  
    20  Unfortunately, manually keeping track of reference counts is extremely error
    21  prone, and improper accounting can lead to production bugs that are very
    22  difficult to root cause.
    23  
    24  We have several ways of discovering reference count errors in gVisor. Any
    25  attempt to increment/decrement a `Refs` struct with a count of zero will trigger
    26  a sentry panic, since the object should have been destroyed and become
    27  unreachable. This allows us to identify missing increments or extra decrements,
    28  which cause the reference count to be lower than it should be: the count will
    29  reach zero earlier than expected, and the next increment/decrement--which should
    30  be valid--will result in a panic.
    31  
    32  It is trickier to identify extra increments and missing decrements, which cause
    33  the reference count to be higher than expected (i.e. a “reference leak”).
    34  Reference leaks prevent resources from being released properly and can translate
    35  to various issues that are tricky to diagnose, such as memory leaks. The
    36  following section discusses how we implement leak checking.
    37  
    38  ## Leak Checking
    39  
    40  When leak checking is enabled, reference-counted objects are added to a global
    41  map when constructed and removed when destroyed. Near the very end of sandbox
    42  execution, once no reference-counted objects should still be reachable, we
    43  report everything left in the map as having leaked. Leak-checking objects
    44  implement the `CheckedObject` interface, which allows us to print informative
    45  warnings for each of the leaked objects.
    46  
    47  Leak checking is provided by `refs_template`, but objects that do not use the
    48  template will also need to implement `CheckedObject` and be manually
    49  registered/unregistered from the map in order to be checked.
    50  
    51  Note that leak checking affects performance and memory usage, so it should only
    52  be enabled in testing environments.
    53  
    54  ## Debugging
    55  
    56  Even with the checks described above, it can be difficult to track down the
    57  exact source of a reference counting error. The error may occur far before it is
    58  discovered (for instance, a missing `IncRef` may not be discovered until a
    59  future `DecRef` makes the count negative). To aid in debugging, `refs_template`
    60  provides the `enableLogging` option to log every `IncRef`, `DecRef`, and leak
    61  check registration/unregistration, along with the object address and a call
    62  stack. This allows us to search a log for all of the changes to a particular
    63  object's reference count, which makes it much easier to identify the absent or
    64  extraneous operation(s). The reference-counted objects that do not use
    65  `refs_template` also provide logging, and others defined in the future should do
    66  so as well.