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
- Cycle Finder Tool - analyzes Java source files for strong object reference cycles.
- Xcode Instruments - Xcode's suite of profiling tools.
- Xcode Memory Diagnostics - build options for running with memory diagnostics and logging.