# How to Implement retain, release, and autorelease Correctly in MulleObjC Mode O

> Master retain release and autorelease in MulleObjC Mode 0. Learn manual object lifetime management with atomic inline helpers for efficient memory control in your Objective-C projects.

- Repository: [mulle-objc/mulleobjc](https://github.com/mulle-objc/mulleobjc)
- Tags: how-to-guide
- Published: 2026-03-07

---

**In MulleObjC Mode O, you balance object lifetimes manually by calling `-retain`, `-release`, and `-autorelease` on `NSObject`, which invoke atomic inline helpers defined in [`src/function/MulleObjCAllocation.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCAllocation.h) to update reference counts.**

MulleObjC Mode O is the classic manual reference-counting environment in the `mulle-objc/mulleobjc` runtime, distinct from Automatic Reference Counting (ARC). Unlike compiler-managed ARC, Mode O requires developers to explicitly manage memory using three fundamental primitives that are implemented as runtime inline functions rather than compiler-generated code.

## Core Memory Management Primitives

MulleObjC Mode O provides **retain**, **release**, and **autorelease** as methods on `NSObject`. Each method maps to low-level atomic operations that directly manipulate the object's reference count.

### The retain Method

The `-retain` method is declared in [`src/class/NSObject.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/class/NSObject.h) at lines 61-73. The implementation lives inline in [`src/function/MulleObjCAllocation.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCAllocation.h) at lines 424-432, where it calls `_mulle_objc_object_retain_inline`. This helper atomically increments the object’s retain-count and returns the same object to the caller.

### The release Method

Declared in [`src/class/NSObject.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/class/NSObject.h) between lines 94-106, the `-release` method invokes `_mulle_objc_object_release_inline` from [`src/function/MulleObjCAllocation.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCAllocation.h) (lines 438-446). This function decrements the retain-count and automatically triggers deallocation via the allocator when the count reaches zero.

### The autorelease Method

The `-autorelease` method appears in [`src/class/NSObject.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/class/NSObject.h) at lines 115-126. Its implementation in [`src/function/MulleObjCAllocation.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCAllocation.h) (lines 350-358) calls `_mulle_objc_object_autorelease` through the universal helper `MulleObjCAutoreleaseAllocation`. This places the object into the current thread’s autorelease pool, which will later send `release` to the object when the pool is drained.

## How Autorelease Pools Function

Autorelease pool mechanics are defined in [`src/class/NSAutoreleasePool.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/class/NSAutoreleasePool.h) and [`src/class/MulleObjCAutoreleasePool.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/class/MulleObjCAutoreleasePool.h). When you create a pool (typically on the stack using `@autoreleasepool`), it captures objects sent `autorelease`. Upon draining, the pool iterates its contents and invokes `_mulle_objc_object_release_inline` on each stored object.

By default, every newly created object returned from `[[MyClass alloc] init]` is **autoreleased** unless you explicitly retain it. This behavior is documented in the comments around line 97 of [`src/class/NSObject.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/class/NSObject.h).

## Thread Safety and Zero-Retain Objects

All low-level helpers (`_mulle_objc_object_retain_inline`, `_mulle_objc_object_release_inline`, and `_mulle_objc_object_autorelease`) are atomic and utilize per-universe thread-foundation information defined in [`src/mulle-objc-universeconfiguration-private.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/mulle-objc-universeconfiguration-private.h).

The runtime also supports **zero-retain objects** for singleton patterns. Allocation helpers in [`MulleObjCAllocation.h`](https://github.com/mulle-objc/mulleobjc/blob/main/MulleObjCAllocation.h) provide variants that do not set an initial retain count of 1. You must call `retain` manually on these objects to establish ownership.

## Correct Implementation Patterns

Use the following pattern to manage object lifecycles in Mode O:

```objc
// 1. Create an object – it is autoreleased by default
id obj = [[MyClass alloc] init];

// 2. Keep it beyond the current autorelease pool
[obj retain];

// … use obj …

// 3. When done, balance the retain
[obj release];

// 4. Explicit pool for temporary objects
@autoreleasepool {
    id temp = [[TempClass alloc] init];
    // use temp
}

```

Each `retain` call must be balanced by exactly one `release` call. Objects created within an `@autoreleasepool` block are released automatically when execution exits the block, so do not send `release` to them unless you have previously sent `retain`.

## Critical Pitfalls to Avoid

- **Over-retaining:** Sending `retain` without a matching `release` causes memory leaks. You can detect this via the `retainCount` method in tests such as `test/NSObject/retainCount.m`.
- **Double-free errors:** Never call `release` on an object you received as autoreleased and did not retain. The pool will release it automatically, causing a double-free if you release it manually.
- **ARC boundary violations:** Manual `retain` and `release` calls are only valid in Mode O. Do not use these methods in ARC-enabled compilation units where the compiler inserts `_mulle_objc_object_retain_inline` and `_mulle_objc_object_release_inline` automatically.

## Summary

- **`-retain`**, **`-release`**, and **`-autorelease`** are declared in [`src/class/NSObject.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/class/NSObject.h) and implemented as atomic inline wrappers in [`src/function/MulleObjCAllocation.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCAllocation.h).
- Default object creation returns autoreleased objects; you must call `retain` to extend an object’s lifetime beyond the current autorelease pool.
- Thread safety is guaranteed through atomic operations using per-universe thread information from [`src/mulle-objc-universeconfiguration-private.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/mulle-objc-universeconfiguration-private.h).
- Balance every `retain` with a `release` to prevent leaks, and never release objects you do not explicitly own.
- Zero-retain allocations exist for singleton patterns but require explicit `retain` calls to establish ownership.

## Frequently Asked Questions

### What distinguishes MulleObjC Mode O from ARC?

MulleObjC Mode O requires explicit manual management using `retain`, `release`, and `autorelease` method calls, whereas ARC (Automatic Reference Counting) inserts these calls at compile time. In Mode O, you directly control the `_mulle_objc_object_retain_inline` and `_mulle_objc_object_release_inline` primitives defined in [`src/function/MulleObjCAllocation.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCAllocation.h).

### Where are the retain and release methods actually implemented?

While declared as methods in [`src/class/NSObject.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/class/NSObject.h), the implementations are inline functions in [`src/function/MulleObjCAllocation.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCAllocation.h). The `retain` method calls `_mulle_objc_object_retain_inline` at lines 424-432, and `release` calls `_mulle_objc_object_release_inline` at lines 438-446, both operating atomically on the object's reference count.

### Can I create objects with no initial retain count?

Yes. MulleObjC supports **zero-retain objects** through specialized allocation helpers in [`MulleObjCAllocation.h`](https://github.com/mulle-objc/mulleobjc/blob/main/MulleObjCAllocation.h). These are useful for implementing singleton patterns, but you must call `retain` manually to take ownership of such objects.

### What happens if I forget to retain an autoreleased object?

The object is released when the enclosing autorelease pool drains, typically at the end of the event loop or `@autoreleasepool` block. Accessing the object afterward results in undefined behavior or crashes. Always send `retain` to objects you need to keep beyond the current scope, as implemented in [`src/class/NSAutoreleasePool.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/class/NSAutoreleasePool.h).