Domanda

La Java virtual machine sposta mai gli oggetti in memoria e, in tal caso, come gestisce l'aggiornamento dei riferimenti all'oggetto spostato?

Lo chiedo perché sto esplorando l'idea di archiviare oggetti in modo distribuito (es.su più server), ma ho bisogno della possibilità di spostare oggetti tra server per motivi di efficienza.Gli oggetti devono essere in grado di contenere puntatori reciproci, anche a oggetti su server remoti.Sto cercando di pensare al modo migliore per aggiornare i riferimenti agli oggetti spostati.

Le mie due idee finora sono:

  1. Mantenere un riferimento indiretto da qualche parte che non si muova per tutta la durata dell'oggetto, che aggiorniamo se l'oggetto si muove.Ma come vengono gestite queste indicazioni indirette?
  2. Mantieni un elenco di riferimenti inversi con ciascun oggetto, così sappiamo cosa deve essere aggiornato se l'oggetto viene spostato.Naturalmente, questo crea un sovraccarico in termini di prestazioni.

Sarei interessato a feedback su questi approcci e ad eventuali suggerimenti per approcci alternativi.

È stato utile?

Soluzione

In riferimento al commento sopra sul camminare nell'heap.

Diversi GC lo fanno in modi diversi.

In genere, copiando i raccoglitori quando percorrono l'heap, non percorrono tutti gli oggetti nell'heap.Piuttosto camminano sugli oggetti LIVE nell'heap.L'implicazione è che se è raggiungibile dall'oggetto "radice", l'oggetto è attivo.

Quindi, in questa fase deve comunque toccare tutti gli oggetti attivi, poiché li copia dal vecchio heap al nuovo heap.Una volta completata la copia degli oggetti attivi, tutto ciò che rimane nel vecchio heap sono oggetti già copiati o spazzatura.A quel punto il vecchio heap potrà essere completamente eliminato.

I due vantaggi principali di questo tipo di raccoglitore sono che compatta l'heap durante la fase di copia e che copia solo oggetti viventi.Questo è importante per molti sistemi perché con questo tipo di raccoglitore, l'allocazione degli oggetti è poco costosa, letteralmente poco più che incrementare un puntatore heap.Quando si verifica GC, nessuno degli oggetti "morti" viene copiato, quindi non rallentano il raccoglitore.Si scopre anche che nei sistemi dinamici c'è molta più piccola spazzatura temporanea che spazzatura di vecchia data.

Inoltre, percorrendo il grafico dell'oggetto live, puoi vedere come il GC può "conoscere" ogni oggetto e tenerne traccia per eventuali scopi di regolazione dell'indirizzo eseguiti durante la copia.

Questo non è il forum per parlare approfonditamente della meccanica GC, poiché è un problema non banale, ma rappresenta la base del funzionamento di un raccoglitore di copie.

Un GC di copia generazionale metterà gli oggetti "più vecchi" in heap diversi e questi finiranno per essere raccolti meno spesso rispetto agli heap "più recenti".La teoria è che gli oggetti di lunga durata vengono promossi alle generazioni più anziane e vengono raccolti sempre meno, migliorando le prestazioni complessive del GC.

Altri suggerimenti

(In pratica) Qualsiasi sistema di garbage collection deve spostare gli oggetti nella memoria per compattarli più densamente ed evitare problemi di frammentazione.

Quello che stai guardando è un argomento molto ampio e complesso.Ti suggerirei di leggere le API esistenti in stile oggetto remoto:.NET remoting e tecnologie più antiche come CORBA

Qualsiasi soluzione per tracciare i riferimenti sarà complicata dal fatto di dover gestire tutte le modalità di guasto esistenti nei sistemi distribuiti.La JVM non deve preoccuparsi di scoprire all'improvviso di non riuscire a vedere metà del suo heap a causa di un guasto allo switch di rete.

Quando approfondisci la progettazione, penso che molto dipenda da come desideri gestire i diversi casi di fallimento.

Risposta ai commenti:

La tua domanda parla dell'archiviazione di oggetti in modo distribuito, che è esattamente ciò che la comunicazione remota .NET e l'indirizzo CORBA.Certo, nessuna delle due tecnologie supporta la migrazione di questi oggetti (AFAIK).Ma entrambi trattano ampiamente i concetti di identità dell'oggetto che è una parte critica di qualsiasi sistema di oggetti distribuiti:come fanno le diverse parti del sistema a sapere di quali oggetti stanno parlando?

Non ho molta familiarità con i dettagli del garbage collector Java e sono sicuro che i garbage collector Java e .NET presentano molta complessità per ottenere le massime prestazioni con il minimo impatto sull'applicazione.

Tuttavia, l'idea di base per la raccolta dei rifiuti è:

  • La VM impedisce a tutti i thread di eseguire codice gestito
  • Esegue un'analisi di raggiungibilità dall'insieme di "radici" note:variabili statiche, variabili locali su tutti i thread.Per ogni oggetto trovato segue tutti i riferimenti all'interno dell'oggetto.
  • Qualsiasi oggetto non identificato dall'analisi di raggiungibilità è spazzatura.
  • Gli oggetti ancora vivi possono quindi essere spostati nella memoria per compattarli densamente.Ciò significa che anche eventuali riferimenti a questi oggetti devono essere aggiornati con il nuovo indirizzo.Controllando quando può verificarsi una raccolta dei rifiuti, la VM è in grado di garantire che non ci siano riferimenti a oggetti "in-the-air" (ad es.tenuto in un registro della macchina) che causerebbe un problema.
  • Una volta completato il processo, la VM riavvia l'esecuzione dei thread.

Come perfezionamento di questo processo, la VM può eseguire la garbage collection generazionale, in cui vengono mantenuti heap separati in base all'età di un oggetto.Gli oggetti iniziano nell'heap 0 e se sopravvivono a diversi GC, migrano all'heap 1 e infine all'heap 2 (e così via: .NET supporta solo 3 generazioni).Il vantaggio di ciò è che il GC può eseguire raccolte heap 0 molto frequentemente e non doversi preoccupare di fare il lavoro per dimostrare che gli oggetti di lunga durata (che sono finiti nell'heap 2) sono ancora vivi (cosa che quasi certamente lo sono) .

Sono disponibili altri perfezionamenti per supportare la Garbage Collection simultanea e dettagli sui thread che eseguono effettivamente codice non gestito quando viene pianificato il GC che aggiungono molta più complessità a quest'area.

Sarei curioso di sapere di più sulle tue esigenze.Come suggerisce un'altra risposta, Terracotta potrebbe essere esattamente quello che stai cercando.

C'è tuttavia una sottile differenza tra ciò che fornisce Terracotta e ciò che chiedi, quindi la mia indagine.

La differenza è che, per quanto ti riguarda, Terracotta non fornisce riferimenti "remoti" agli oggetti - in effetti l'intera nozione "remota" di RMI, JMS, ecc.è completamente assente quando si utilizza Terracotta.

Piuttosto, in Terracotta, tutti gli oggetti risiedono in un grande heap virtuale.I thread, sia sul Nodo 1, sia sul Nodo 2, sul Nodo 3, sul Nodo 4, ecc., hanno tutti accesso a qualsiasi oggetto nell'heap virtuale.

Non c'è programmazione speciale da apprendere o API speciali, gli oggetti nell'heap "virtuale" hanno esattamente lo stesso comportamento degli oggetti nell'heap locale.

In breve, ciò che Terracotta fornisce è un modello di programmazione per più JVM che funziona esattamente come il modello di programmazione per una singola JVM.I thread in nodi separati si comportano semplicemente come thread in un singolo nodo: le mutazioni degli oggetti, la sincronizzazione, l'attesa, la notifica si comportano esattamente allo stesso modo tra i nodi e tra i thread - non c'è differenza.

Inoltre, a differenza di qualsiasi soluzione precedente, i riferimenti agli oggetti vengono mantenuti tra i nodi, il che significa che puoi utilizzare ==.Fa tutto parte del mantenimento del modello di memoria Java nel cluster, che è il requisito fondamentale per rendere Java "normale" (ad es.POJO, sincronizzati, attesa/notifica) funzionano (nessuno di questi funziona se non si/non è possibile preservare l'identità dell'oggetto nel cluster).

Quindi ti ritorna la domanda per perfezionare ulteriormente i tuoi requisiti: per quale scopo hai bisogno di puntatori "remoti"?

La parola chiave che stai cercando è "compattazione del garbage collector".Le JVM possono usarne una, il che significa che gli oggetti possono essere riposizionati.Consulta il manuale della tua JVM per scoprire se il tuo lo fa e per vedere se ci sono opzioni della riga di comando che lo influenzano.

Il modo concettualmente più semplice per spiegare la compattazione è presupporre che il garbage collector congeli tutti i thread, riposiziona l'oggetto, cerca nell'heap e nello stack tutti i riferimenti a quell'oggetto e li aggiorna con il nuovo indirizzo.In realtà è più complesso di così, poiché per motivi di prestazioni non si desidera eseguire una scansione completa con i thread in stallo, quindi un garbage collector incrementale lavorerà in preparazione alla compattazione ogni volta che può.

Se sei interessato ai riferimenti indiretti, potresti iniziare ricercando i riferimenti deboli e soft in Java e anche i riferimenti remoti utilizzati da vari sistemi RPC.

sembra che tu stia cercando una cache distribuita, qualcosa come terracotta o cache objece Java di Oracle (precedentemente tangersol).

Se sei disposto ad approfondire, puoi dare un'occhiata ai documenti sull'architettura di JBoss Cache e prendere parte del suo codice sorgente come riferimento.

Questo non è esattamente quello che hai descritto, ma funziona in modo molto simile.

Ecco il collegamento.

http://www.jboss.org/jbosscache/

Spero che aiuti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top