2015-04-15 7 views
5

https://developer.gnome.org/glib/unstable/glib-GVariant.html#g-variant-ref-sinkQuando rimuovere un GVariant che ha un riferimento mobile?

Ho letto quanto sopra manuale glib che dice: "GVariant utilizza un sistema di conteggio di riferimento flottante tutte le funzioni con nomi che iniziano con g_variant_new_ ritorno riferimenti galleggianti." Ma dove è la descrizione reale di ciò che un galleggiante il conteggio dei riferimenti è? Non ho potuto trovare una descrizione completa di esso.

In particolare, desidero capire quando è necessario deselezionare una variante e quando no. Per esempio:

GVariant *a_v = g_variant_new_boolean(TRUE); 
GVariant *another_v = g_variant_new("v", a_v); 
  1. penso che non ho bisogno di unreference a_v perché è consumato dal secondo g_variant_new. È corretto?
  2. Devo annullare il riferimento another_v (supponendo che another_v non venga passato a nessun altro da quel punto in poi)?
  3. Dove è documentato? (Penso di avere la giusta comprensione, deducendo da diversi esempi trovati durante la ricerca, ma non riesco a trovare la documentazione ufficiale che spiega questo chiaramente).

risposta

7

C'è una sezione su floating references nel manuale di riferimento di GObject che va un po 'più in dettaglio. I riferimenti fluttuanti possono sembrare un po 'oscuri, ma sono davvero molto utili per C, quindi prendere qualche minuto per capirli davvero è una buona idea.

Suppongo che tu capisca come funziona il conteggio dei riferimenti - se non c'è molta documentazione là fuori, prenditi qualche minuto e leggi quanto prima.

Prima di tutto, vediamo cosa accadrebbe nell'esempio se g_variant_new_boolean restituisse un riferimento regolare. Quando si ottiene il valore per la prima volta, il conteggio dei riferimenti sarà 1. Quando lo si passa a g_variant_new, g_variant_new aumenterà il conteggio dei riferimenti a 2. Ad un certo punto presumo che si disponga di another_v, a quel punto il conteggio dei riferimenti per a_v scenderà a 1 ... ma ricorda, la memoria non viene rilasciata fino a quando il conteggio dei riferimenti raggiunge 0.

Per aggirare questo hai due opzioni.Il primo è quello di rendere g_variant_new rubare il riferimento del chiamante, che in sostanza fa schifo come soluzione. Dacci via il tuo riferimento quando chiami g_variant_new (o qualsiasi funzione simile), quindi in futuro dovrai rifare manualmente a_v ogni volta che vuoi passarlo a qualcos'altro.

L'altra opzione è quella di sfilarlo manualmente una volta terminato. Non è la fine del mondo, ma è facile dimenticare di fare o sbagliare (ad esempio dimenticando di slegarlo in un percorso di errore).

Ciò che invece GVariant restituisce è un riferimento "mobile". Il modo più semplice per pensarci (IMHO) è che la prima volta che viene chiamato g_variant_ref non fa veramente niente, semplicemente "affonda" il riferimento fluttuante. Il conteggio dei riferimenti va da 1 a 1. Successive chiamate a g_variant_ref, tuttavia, aumenterà il conteggio dei riferimenti.

Ora vediamo cosa succede realmente con il tuo esempio. g_variant_new_boolean restituisce un riferimento mobile. Si passa quindi a g_variant_new, che chiama g_variant_ref, che affonda il riferimento mobile. Il conteggio dei riferimenti ora è 1, e quando il conteggio di another_v raggiunge il numero 0 a_v, il conto verrà decrementato, in questo caso si raggiunge 0 e tutto sarà liberato. Non c'è bisogno che tu chiami il numero g_variant_unref.

La parte interessante di riferimenti galleggiante, però, è quello che succede con qualcosa di simile:

GVariant *a_v = g_variant_new_boolean(TRUE); 
GVariant *another_v = g_variant_new("v", a_v); 
GVariant *yet_another_v = g_variant_new("v", a_v); 

Quando g_variant_new si chiama la seconda volta a_v s' refcount incrementerà di nuovo (a 2). Non è necessario chiamare lo g_variant_ref prima di passare a_v a g_variant_new una seconda volta: la prima chiamata appare come la prima e la coerenza è una funzionalità molto bella in un'API.

A questo punto è probabilmente ovvio, ma sì, è necessario chiamare g_variant_unref su another_v (e, in quest'ultimo esempio, yet_another_v).

+0

Ottima spiegazione. Grazie per aver dedicato del tempo per spiegarlo in dettaglio. – kaylum

+0

Puoi spiegarlo per favore "e quando il conteggio di another_v raggiunge 0 il conteggio di a_v sarà decrementato". Quando il conto di un'altra_v arriverà a 0? –

+0

Ogni qualvolta un altro codice chiama 'g_variant_unref (another_v)'. Fondamentalmente, quando il contenitore ('another_v') viene distrutto, decrementerà anche il conteggio di riferimento di a_v'. Dal momento che quel conto è 1 prima della chiamata, decrementandolo lo ridurrà a 0, il che significa che sarà liberato. La rilettura del terzo paragrafo (che descrive cosa succede per ** non ** - riferimenti mobili) potrebbe essere utile. – nemequ

0

Il sistema di conteggio di riferimento è spiegato nel manuale di GObject, in particolare nella sezione Object Memory Management.

Quando usarlo potrebbe dipendere dall'applicazione (come funzionerà la proprietà delle variabili).

L'idea è simile al modo in cui i-node funziona in Unix/Linux durante la gestione dei file. Un file è un oggetto, situato in un blocco specifico nella memoria. Ogni volta che si crea un collegamento simbolico a quel file, il file è di proprietà con un file aggiuntivo (il conteggio dei riferimenti aumenta). Ogni volta che rimuovi un collegamento simbolico, il conteggio dei riferimenti diminuisce. Quando non c'è nulla che possegga l'oggetto, allora può essere distrutto (o lo spazio può essere restituito al sistema).

Se si distrugge un oggetto e nulla sta collegando quell'oggetto, non è più possibile utilizzarlo. Se il tuo oggetto potrebbe avere più proprietari, allora potresti voler usare il conteggio dei riferimenti, quindi quando uno di questi proprietari rimuove un contatore, l'oggetto non viene distrutto ... no fino a quando l'ultimo proprietario non lo distrugge.

+0

Grazie per il puntatore e la spiegazione. Ma entrambi sembrano riguardare il conteggio dei riferimenti "completo". Capisco che l'aspetto dei riferimenti conta. Quello che non capisco completamente è in particolare conteggi di riferimento "fluttuanti". Giusto per illustrare che esiste il concetto di conteggi ref full vs floating, dal manuale di glib: "Chiamare g_variant_ref_sink() su un GVariant con un riferimento mobile convertirà il riferimento mobile in un riferimento completo." – kaylum

+0

Infatti, riguardano il conteggio completo dei riferimenti. Ho sbagliato la tua domanda :-) – gpoo

Problemi correlati