J2ObjC メモリモデル

このドキュメントでは、J2ObjC 変換コードでメモリを管理する方法と、共有メモリにアクセスする際のプログラムの動作について説明します。

メモリ管理

J2ObjC の目標の 1 つは、Objective-C のリファレンス カウント環境にシームレスに統合する翻訳版コードを作成することです。これにより、Java 環境と Objective-C 環境の間で渡されるオブジェクトの所有権を不自然な方法で譲渡することがないため、ネイティブに記述された Objective-C から変換された Java コードを簡単に使用できるようになります。

Java はメモリ管理にガベージ コレクションを使用するため、Java コードにはオブジェクトの明示的なメモリ管理は含まれません。そのため、J2ObjC は、適切なタイミングでオブジェクトの割り当てが解除されるように、参照カウント呼び出しを適切に挿入する必要があります。パフォーマンスが高く実用的であることが判明した次のルールセットを設定しています。

  • すべてのオブジェクトは、少なくとも現在の自動リリース プールが存続する間は存続します。
    • この一般的なルールにより、他の方法では必要になる多くの保持とリリースをスキップできます。
  • ローカル変数は保持されません。
    • ローカル変数の読み取りまたは書き込みに対する参照カウントの呼び出しはありません。
  • フィールドは保持されます。
    • フィールド呼び出しの割り当ては新しい値で保持され、古い値が自動的に解放されます。
  • 新しいオブジェクトは直ちに自動解放されます。(フィールドに直接割り当てられている場合を除く)

基準周期

参照サイクルは、オブジェクトがフィールドを通じて直接的または間接的に自身を参照する場合に存在します。参照サイクルは Java のガベージ コレクションでクリーンアップできますが、Objective-C の参照カウント環境でメモリリークが発生します。参照サイクルの発生を自動的に防ぐ方法はありませんが、サイクルの検出を自動化する Cycle Finder ツールをご利用いただけます。基準周期を修正する一般的な方法をいくつか紹介します。

  • 一方の参照を弱めるには、@Weak または @WeakOuter のアノテーションを追加します。
  • 一部のフィールドを null に設定するオブジェクトの 1 つに、cleanup() メソッドを追加します。オブジェクトを破棄する前に cleanup() を呼び出します。
  • 参照サイクルが作成されないようにコードを再設計する。

共有メモリ

マルチスレッド プログラムでは、一部のデータが複数のスレッドによって共有される場合があります。Java には、共有データへのスレッドセーフなアクセスを許可するツールがいくつか用意されています。このセクションでは、共有データへのアクセスに対する J2ObjC のサポートについて説明します。

同期

J2ObjC は、synchronized キーワードを Objective-C の @synchronized に直接マッピングします。

アトミック性

Java は、longdouble を除くすべての型の読み込みとストアに対して、アトミック性を保証します。JLS-17.7 をご覧ください。volatile フィールド(以下で説明)を除き、J2ObjC にはアトミックな読み込みとストアを確保するための特別な処理はありません。つまり、次のようになります。

  • iOS プラットフォームはすべて 32 ビットまたは 64 ビットであるため、longdouble を除くプリミティブ型の読み込みと保存は、32 ビットデバイスではアトミックに実行され、64 ビットシステムではすべてがアトミックに実行されます。
  • J2ObjC では、オブジェクト型のロードとストアはアトミックではありません。
    • 参照数をアトミックに更新するとコストがかかります。
    • オブジェクト フィールドは volatile と宣言することでアトミックにできます。(下記をご覧ください)。

揮発性フィールド

volatile フィールドの場合、Java はアトミック性とシーケンシャルな順序付けの両方を提供し(JLS-8.3.1.4)、同期に使用できます。J2ObjC は、すべての volatile フィールドについて Java と同じ保証を提供します。J2ObjC は、volatile フィールドに次のメカニズムを使用します。

  • プリミティブ型は c11 のアトミック型にマッピングされます。
    • 例: volatile int -> _Atomic(jint)
  • オブジェクト フィールドは、pthread ミューテックス ロックによって保護されます。(優先順位の逆転によりスピンロックを使用できません)
    • 参照カウントとの競合状態を防ぐには相互除外が必要です。
    • 実装は、Objective-C のアトミック プロパティと非常によく似ています。

アトミック型

Java では、多数のアトミック型が java.util.concurrent.atomic パッケージに用意されています。これらはすべて、カスタム実装を使用する J2ObjC で完全にサポートされています。

最後のフィールド

Java では、オブジェクトを共有するときに同期を必要とせずに、スレッドがオブジェクトの final フィールドの初期化値を参照することが保証されます。(JSL-17.5)ただし、J2ObjC は不揮発性オブジェクト型のアトミック アクセス(上記参照)をサポートしていないため、同期せずにオブジェクトを共有する安全な方法はありません。したがって、final フィールドに必要なメモリフェンスを省略しても、J2ObjC ユーザーには追加の制約は適用されません。