Eroxl's Notes
Reference Counting

Reference counting is a method of managing memory to decrease the risks common memory pitfalls like memory leaks or dangling pointers. Reference counting follows 4 basic rules to perform this

  1. Initialize the reference count to one (as the caller has a reference)
  2. Any procedure that stores a reference increments the count
  3. Any procedure that discards a reference decrements the count
  4. Never free an object directly, instead the object is free when the count goes to zero

General Examples

When a Reference is a Parameter

When a reference is passed to a procedure as a parameter, the caller necessarily must maintain it for the duration of the call so the callee doesn't need to call keep_ref, unless the callee saves the pointer somewhere that will outlast the call (ie. a global variable), or the callee returns the pointer to the caller.

When a Reference is a Return Value

When a reference is returned from a procedure, the callee must have a reference to the value which it returns to the caller, when it returns it though it transfers that reference to the caller, it's then the callers responsibility to call free_ref when it no longer needs the reference.

When a Reference is Stored in a Local Variable

References' stored in local variables necessarily must go away when the procedure returns so the procedure must call free_ref before it returns.

Implementations

Concrete Type

If the struct you're reference counting has a concrete type reference counting can be implemented as follows:

struct buffer *rc_malloc() {
	struct buffer *buf = malloc(sizeof(struct buffer));
	buf->ref_count = 1;

	return buf;
}

void rc_keep_ref(struct buffer *buf) {
	buf->ref_count++;
}

void rc_free_ref(struct buffer *buf) {
	buf->ref_count--;
	
	if (buf->ref_count == 0) free(buf);
}

General Type

A more general method can be used which works for any input type, this is done by reserving 8 bytes before the actual allocated memory for the ref count.

void* rc_malloc(int num_bytes) {
	// Add 8 bytes to store the ref_count
	int *ref_count = malloc(n+8);
	*ref_count = 1;
	
	return ((void*) ref_count) + 8;
}

void rc_keep_ref(void* ptr) {
	int *ref_count = ptr - 8;
	(*ref_count)++;
}

void rc_free_ref(void* ptr) {
	int *ref_count = ptr - 8;
	(*ref_count)--;
	
	if (*ref_count == 0) free(ref_count);
}