Memory Management

The first question most Java developers have is how is memory management implemented by J2ObjC, since Java has garbage collection and Objective-C doesn't by default. What iOS does have are two methods of memory management: reference counting, and Automatic Reference Counting (ARC).

J2ObjC generates different memory management code, depending on which method is chosen. Translate with the -use-arc option to generate code which uses ARC. By default it uses manual reference counting.

Reference Counting

The reference counting method makes object ownership explicit. A method owns an object when it creates it, until it releases that object. When receiving an object from another method, the receiving method retains the object if it needs to be referenced after the method returns. When a method no longer needs to reference an object, it must release it. When an object's retain count is zero, its memory is freed and the object is no longer valid. When objects are freed, their dealloc() method is called to release ownership of their instance variables.

One problem with this technique is how to transfer ownership of an object. For example, a factory method may be called to create an object. If the factory method releases the object before returning it (since it no longer wants to own the object), then that object is freed before the calling method can retain it.

To transfer ownership of an object, a method sends it an autorelease message (instead of a release message), which defers the release message. This allows the factory method to create an object to be returned, and relinquish its ownership without invalidating the object. At regular intervals (such as after each event loop iteration in an iOS application) the autorelease pool is "drained", meaning all objects in that pool are sent the deferred release messages. Any objects whose retain counts drop to zero are freed as normal.

Because the burden on memory management is on the developer, it's easy to leak memory with the reference counting method. However, Apple recommends some best practices to minimize this problem, which J2ObjC implements.

There is also runtime and tool support to detect memory leaks. The Objective-C runtime reports any detected leaks when an application exits, which is one reason why J2ObjC translates JUnit tests into executable binaries. Xcode uses Clang, and that compiler has excellent static analysis for memory problems, which Xcode makes available with its Analyze command.

Automatic Reference Counting (ARC)

ARC is Apple's recommended memory management method. It moves the responsibility for reference counting to the compiler, which adds the appropriate retain, release and autorelease methods during compilation. ARC supports weak references for devices running iOS 5 and later.

We recommend that projects use ARC for translated code. Transpiled Objective-C code is just like hand-written Objective-C code. Using ARC could help developers avoid common memory-related errors such as over-releasing or under-referencing, making memory management simpler and less error-prone.

Note that ARC is not exception-safe by default. Specifically, it leaks memory when exceptions are thrown. Since exceptions are more common in Java and are usually recoverable, this can be problematic. Using -fobjc-arc-exceptions when compiling with arc will fix the leaks with some acceptable performance cost.

We also recommend that new projects use ARC for their hand-written Objective-C code, and only fall-back to manual reference counting if profiling data shows a real performance issue. Both ARC and non-ARC code can be compiled and linked into the same app without issue.

Weak References

Fields can be annotated with com.google.devtools.j2objc.Weak, which the transpiler uses to generate fields that follow Objective-C weak reference semantics. When using reference counting, this means that the field is not retained when initialized, and it is autoreleased when the containing instance is released. With ARC, weak fields are marked with the __unsafe_unretained annotation, and the related properties are declared weak.

In some cases, an inner class instance gets in a reference cycle with its outer instance. Here, a com.google.devtools.j2objc.WeakOuter annotation is used to mark the inner class, so the reference to the outer class is treated as described above. Other fields in the inner class are not affected by this annotation.

J2ObjC also supports the WeakReference class, so Java code that uses it will work the same way when translated. Be aware that WeakReference is inherently nondeterministic on the JVM; applications that want to avoid memory leaks while maintaining predictability should instead prefer @Weak and @WeakOuter.

Memory Management Tools