Modello di memoria J2ObjC

Questo documento descrive come la memoria viene gestita nel codice tradotto J2ObjC e come si comportano i programmi quando accedono alla memoria condivisa.

Gestione della memoria

Uno degli obiettivi di J2ObjC è produrre codice tradotto che si integri perfettamente nell'ambiente di conteggio dei riferimenti di Objective-C. Questo rende il codice Java tradotto facile da usare da Objective-C scritto in modo nativo, in quanto non esiste un trasferimento imbarazzante della proprietà degli oggetti passati tra gli ambienti Java e Objective-C.

Poiché Java utilizza la garbage collection per la gestione della memoria, il codice Java non contiene alcuna gestione esplicita della memoria dei suoi oggetti. J2ObjC deve quindi inserire le chiamate per il conteggio dei riferimenti in modo appropriato per garantire che gli oggetti vengano distribuiti al momento giusto. Abbiamo stabilito la seguente serie di regole che abbiamo riscontrato essere efficaci e pratiche:

  • Tutti gli oggetti saranno attivi per almeno la durata del pool di rilascio automatico corrente.
    • Questa regola generale ci consente di ignorare molte conservazioni e release che sarebbero altrimenti necessarie.
  • Le variabili locali non vengono conservate.
    • Nessuna chiamata di conteggio del riferimento alle operazioni di lettura o scrittura di variabili locali.
  • I campi vengono conservati.
    • L'assegnazione delle chiamate di campo viene mantenuta in base al nuovo valore e viene rilasciata automaticamente sul valore precedente.
  • I nuovi oggetti vengono immediatamente rilasciati automaticamente. (a meno che non venga assegnata immediatamente a un campo)

Cicli di riferimento

Un ciclo di riferimento si verifica quando un oggetto fa riferimento a se stesso, direttamente o indirettamente, attraverso i suoi campi. I cicli di riferimento possono essere ripuliti dalla garbage collection di Java, ma perdono memoria nell'ambiente di conteggio dei riferimenti di Objective-C. Non esiste un modo automatico per impedire il verificarsi dei cicli di riferimento; tuttavia, mettiamo a disposizione uno strumento Cycle Finder che automatizza il rilevamento dei cicli. Di seguito sono riportati alcuni modi comuni per correggere un ciclo di riferimento:

  • Aggiungi un'annotazione @Weak o @WeakOuter per indebolire uno dei riferimenti.
  • Aggiungi un metodo cleanup() a uno degli oggetti che impostano alcuni campi su null. Chiama cleanup() prima di eliminare l'oggetto.
  • Riprogettare il codice per evitare di creare del tutto un ciclo di riferimento.

Memoria condivisa

In un programma multi-thread, alcuni dati possono essere condivisi da più thread. Java offre diversi strumenti per consentire l'accesso thread-safe ai dati condivisi. Questa sezione descrive il supporto di J2ObjC per l'accesso ai dati condivisi.

Sincronizzata

J2ObjC mappa la parola chiave synchronized direttamente all'obiettivo C @synchronized.

Atomicità

Java garantisce l'atomicità per carichi e archivi di tutti i tipi tranne long e double. Vedi JLS-17.7. Ad eccezione dei campi volatile (descritti di seguito), J2ObjC non offre alcun trattamento speciale per garantire carichi e negozi atomici. Ciò implica quanto segue:

  • Poiché tutte le piattaforme iOS sono a 32 o 64 bit, i carichi e gli archivi di tipi primitivi, ad eccezione di long e double, sono atomici su dispositivi a 32 bit e sono tutti atomici su sistemi a 64 bit.
  • I carichi e gli archivi di tipi di oggetti non sono atomici in J2ObjC.
    • L'aggiornamento atomico dei conteggi dei riferimenti è troppo costoso.
    • Un campo oggetto può essere reso atomico dichiarandolo volatile. Leggi la sezione che segue per saperne di più.

Campi volatili

Per i campi volatile, Java fornisce sia l'atomicità sia l'ordinamento coerente in sequenza (JLS-8.3.1.4), che possono essere utilizzati per la sincronizzazione. J2ObjC offre le stesse garanzie di Java per tutti i campi volatile. J2ObjC utilizza i seguenti meccanismi per i campi volatile:

  • I tipi primitivi sono mappati ai tipi atomici c11.
    • Ad esempio: volatile int -> _Atomic(jint)
  • I campi degli oggetti sono protetti con blocchi mutex pthread. (non è possibile utilizzare il blocco spin a causa dell'inversione della priorità)
    • L'esclusione reciproca è necessaria per evitare le condizioni di gara con il conteggio dei riferimenti.
    • L'implementazione è molto simile alle proprietà atomiche di Objective-C.

Tipi atomici

Java fornisce diversi tipi atomici nel pacchetto java.util.concurrent.atomic. Sono tutti completamente supportati in J2ObjC con implementazioni personalizzate.

Campi finali

Java garantisce che un thread veda i valori inizializzati per i campi finali di un oggetto senza richiedere alcuna sincronizzazione durante la condivisione dell'oggetto. (JSL-17.5) Tuttavia, poiché J2ObjC non supporta l'accesso atomico dei tipi di oggetti non volatili (vedi sopra), non esiste un modo sicuro per condividere un oggetto senza sincronizzazione. Pertanto, non vengono applicati vincoli aggiuntivi all'utente J2ObjC, omettendo i recuperi di memoria necessari per i campi finali.