2009-11-09 10 views
5

Molti anni fa, mi è stato chiesto di rilasciare, quando possibile, le risorse in ordine inverso rispetto al modo in cui sono state assegnate. Ovvero:C#: Esiste un vantaggio nello smaltimento delle risorse in ordine inverso rispetto alla loro assegnazione?

block1 = malloc(...); 
block2 = malloc(...); 

... do stuff ... 

free(block2); 
free(block1); 

Immagino su una macchina MS-DOS 640K, questo potrebbe minimizzare la frammentazione dell'heap. C'è un vantaggio pratico a fare questo in un'applicazione C# /.NET, o è un'abitudine che è sopravvissuta alla sua rilevanza?

risposta

5

Se le risorse vengono create bene, questo non dovrebbe importare (molto).

Tuttavia, molte librerie malamente create non eseguono il controllo corretto. Smaltire le risorse al contrario della loro allocazione significa in genere che si stanno eliminando risorse dipendenti da altre risorse per prime, il che può impedire alle librerie scritte in modo insufficiente di causare problemi. (Non disponi mai di una risorsa, quindi usane una che dipende dalla prima esistenza in questo caso.)

È anche una buona pratica, dal momento che non disporrai accidentalmente una risorsa richiesta da qualche altro oggetto troppo presto .

Ecco un esempio: osservare un'operazione del database. Non si desidera chiudere/disporre la connessione prima di chiudere/eliminare il comando (che utilizza la connessione).

+0

Creato bene non va bene. Deve essere dipendente dall'ordine, dipendente dal rilascio e conosciuto in molte circostanze. Non potrebbe importare di più in tutte le implementazioni di database, transazioni e tutto ciò che viene eseguito su uno stack (la maggior parte dei software là fuori). I lock sono un altro esempio e ci sono pile di librerie non esterne e non povere che lo usano. Le operazioni sui file e i loro blocchi sono un'altra. Event leakage another. Qualsiasi risorsa non gestita a seconda di un'altra. Creazione e distruzione vanno di pari passo, e l'idioma non può essere preso a scatti come Inizializzazione delle risorse-È- "ben-Creazione". –

+0

Così che il WC nell'ossimauro RIIWC viene sostituito con Aquisition, che implica una Release btw. E dal momento che la memoria e il gran numero di risorse sono per lo più astratte, ops, ecco l'idea ... e ne conseguono hack di ogni tipo. In breve, è semplicemente la natura del problema e conta molto. –

+0

E anche se non sto difendendo la dipendenza dall'ordine, l'osservazione corretta è che è estremamente rilevante ma raramente desiderabile. Ma è qualcosa che persino le specifiche ufficiali di VM sono limitate a. Java impl in particolare e CLR in misura minore ma ancora significativa. È un trucco per non rompere grandi corpus di codice funzionante e ipotesi fatte, una decisione concisa da parte del compilatore e dei progettisti di backend di jit. Il codice che è in grado di elaborare in modo indipendente dall'ordine si presta a una vasta gamma di possibilità, ma può essere impossibile per molti scenari. –

4

Non disturbare. GarbageCollector si riserva il diritto di deframmentare e spostare gli oggetti nell'heap, quindi non si può sapere quale sia l'ordine.

Inoltre, se si dispone dei riferimenti A e B e A B non dovrebbe importare se A dispone B quando disponi A, poiché il metodo Dispose dovrebbe essere richiamabile più volte senza che venga lanciata un'eccezione.

+1

vero, a patto di non utilizzare un "disposto "riferimento per errore (tramite un altro oggetto creato da esso), poiché si dispone in ord arbitrario ER. –

0

"usings" nidificati ti mostra che il "sopravvissuto" non è realmente attivo e raramente lo è (non andare a dire mai dopo 40 anni di prove) .. E questo include la VM basata su stack che viene eseguita su CMOS .

[Nonostante alcuni tentativi da parte di MSDN.com e Duffius di farlo sparire, è possibile gestirli tutti per la differenza tra l'heap e lo stack. Che idea intelligente ... nello spazio]

1

Se si fa riferimento al momento in cui viene chiamato il distruttore sugli oggetti, quindi è il garbage collector, la programmazione può avere pochissima influenza su di esso ed è esplicitamente non deterministico in base alla definizione del linguaggio.

Se si fa riferimento alla chiamata IDisposable.Dispose(), ciò dipende dal comportamento degli oggetti che implementano l'interfaccia IDisposable.

In generale, l'ordine non è rilevante per la maggior parte degli oggetti Framework, tranne nella misura in cui è rilevante per il codice chiamante. Ma se l'oggetto A mantiene una dipendenza dall'oggetto B e l'oggetto B è disposto, allora potrebbe essere molto importante non fare certe cose con l'oggetto A.

Nella maggior parte dei casi, Dispose() non viene chiamato direttamente, ma piuttosto è chiamato implicitamente come parte di un'istruzione using o foreach, nel qual caso il modello di ordine inverso emergerà naturalmente, secondo l'incorporamento dell'istruzione.

using(Foo foo = new Foo()) 
using(FooDoodler fooDoodler = new FooDoodler(foo)) 
{ 
    // do stuff 
    // ... 
    // fooDoodler automatically gets disposed before foo at the end of the using statement. 
} 
0

"Il runtime non fa alcuna garanzia in quanto alle nell'ordine in cui finalizzare metodi sono chiamati. Ad esempio, supponiamo che v'è un oggetto che contiene un puntatore a un oggetto interno.Il garbage collector ha rilevato che entrambi gli oggetti sono spazzatura. Inoltre, dì che il metodo Finalize dell'oggetto interno viene chiamato per primo. Ora, il metodo Finalize dell'oggetto esterno può accedere all'oggetto interno e chiamare i metodi su di esso, ma l'oggetto interno è stato finalizzato ei risultati potrebbero essere imprevedibili. Per questo motivo, si consiglia vivamente che i metodi Finalize non accedere a qualsiasi, oggetti membro interno ".

http://msdn.microsoft.com/en-us/magazine/bb985010.aspx

Così si può preoccupare i tuoi LIFO smaltire semantica quanto si vuole, ma se si Leak uno, il Dispose (s ') stanno per essere chiamati in qualsiasi ordine le fantasie CLR.

(questo è più o meno quello che ha detto Will, sopra)