A toolkit for implementing Reference Counting resource management in Java. This library provides a framework for deterministic resource management through reference counting, similar to how languages like C++ and Rust handle memory management.
Java's garbage collector provides automatic memory management, but it doesn't offer deterministic resource cleanup. This can be problematic when working with:
- Native resources (e.g., GPU memory, file handles)
- Large objects that need timely cleanup
- Resources that require ordered cleanup sequences
The Java Reference Counter toolkit solves this by providing:
- A reference counting base class for creating reference-counted objects
- Reference-aware collection wrappers that properly manage element lifecycles
- A Maven plugin (autocoder) that automatically instruments your code with reference counting operations
| Module | Artifact ID | Description |
|---|---|---|
| core | refcount-core |
Core runtime library with base classes, interfaces, and reference-counted collection wrappers |
| autocoder | autocoder-core |
Base Maven plugin infrastructure for AST transformation |
| refcount-autocoder | refcount-autocoder |
Maven plugin that automatically instruments code with reference counting operations |
| autocoder-test | autocoder-test |
Test utilities for the autocoder |
| demo | demo |
Example implementations demonstrating usage patterns |
Add the core library to your project:
<dependency>
<groupId>com.simiacryptus</groupId>
<artifactId>refcount-core</artifactId>
<version>2.1.0</version>
</dependency>Extend ReferenceCountingBase to create objects with automatic reference counting:
import com.simiacryptus.ref.lang.ReferenceCountingBase;
public class MyResource extends ReferenceCountingBase {
private byte[] data;
public MyResource(int size) {
this.data = new byte[size];
}
public void doWork() {
assertAlive(); // Throws if object has been freed
// ... use the resource
}
@Override
protected void _free() {
// Clean up resources when reference count reaches zero
data = null;
super._free();
}
}// Create a reference-counted object (starts with refcount = 1)
MyResource resource = new MyResource(1024);
// Pass to another owner - increment reference count
MyResource ref2 = resource.addRef();
// When done with a reference, decrement count
resource.freeRef();
// Object is freed when last reference is released
ref2.freeRef(); // _free() is called hereThe library provides reference-aware wrappers for standard Java collections:
import com.simiacryptus.ref.wrappers.*;
// Reference-counted ArrayList
RefArrayList<MyResource> list = new RefArrayList<>();
list.add(new MyResource(100));
// Elements are properly reference-counted
MyResource item = list.get(0); // Returns a new reference
item.freeRef(); // Release when done
// Free the list (also frees contained elements)
list.freeRef();Available collection wrappers include:
RefArrayList,RefLinkedListRefHashMap,RefLinkedHashMap,RefTreeMap,RefConcurrentHashMapRefHashSet,RefTreeSetRefStream,RefDoubleStream,RefIntStream,RefLongStreamRefIterator,RefSpliterator- And more...
| Interface/Class | Description |
|---|---|
ReferenceCounting |
Core interface defining reference counting operations (addRef(), freeRef(), isFreed(), etc.) |
ReferenceCountingBase |
Abstract base class implementing ReferenceCounting with lifecycle debugging support |
RefUtil |
Utility methods for working with reference-counted objects |
| Annotation | Description |
|---|---|
@RefAware |
Marks a parameter/return value as being reference-aware (caller owns the reference) |
@RefIgnore |
Marks code that should be ignored by the autocoder |
@MustCall |
Indicates a method that must be called (used for _free() override) |
public interface ReferenceCounting {
ReferenceCounting addRef(); // Increment reference count
int freeRef(); // Decrement reference count
boolean isFreed(); // Check if object has been freed
int currentRefCount(); // Get current reference count
boolean assertAlive(); // Assert object is not freed
boolean tryAddRef(); // Try to add reference (returns false if freed)
ReferenceCounting detach(); // Detach from reference counting
}The refcount-autocoder Maven plugin can automatically instrument your code with reference counting operations, reducing boilerplate and preventing resource leaks.
<build>
<plugins>
<plugin>
<groupId>com.simiacryptus</groupId>
<artifactId>refcount-autocoder</artifactId>
<version>2.1.0</version>
<executions>
<execution>
<goals>
<goal>insert</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>| Goal | Description |
|---|---|
insert |
Insert reference counting operations into source code |
remove |
Remove reference counting operations from source code |
verify |
Verify that reference counting is correctly implemented |
check |
Check code for reference counting issues |
The library includes comprehensive debugging support for tracking reference leaks:
// Watch specific objects for debugging
resource.watch();
// Get detailed reference report
String report = ReferenceCountingBase.referenceReport(resource, true);Lifecycle debugging is configured through environment variables or system properties:
| Variable | Description | Default |
|---|---|---|
DEBUG_LIFECYCLE |
Enable lifecycle debugging for all classes | false |
WATCH_ENABLE |
Enable watch functionality | true |
WATCH_CREATE |
Track creation stack traces | false |
# Enable lifecycle debugging
export DEBUG_LIFECYCLE=true
# Or via system property
java -DDEBUG_LIFECYCLE=true -jar myapp.jarDebug output includes:
- Stack traces where objects were created
- Stack traces for each
addRef()call - Stack traces for each
freeRef()call - Current reference count and state
- Always free references - Every
addRef()must have a correspondingfreeRef() - Use try-finally - Ensure
freeRef()is called even when exceptions occur - Check
assertAlive()- Call in methods that use the resource - Override
_free()- Release resources when reference count reaches zero - Use the autocoder - Let the plugin manage reference counting automatically
MyResource resource = new MyResource(1024);
try {
resource.doWork();
} finally {
resource.freeRef();
}This project is licensed under the Apache License 2.0. See LICENSE for details.
Copyright (c) 2020 by Andrew Charneski