La memoria .Net è affamata?

3

Un mio amico mi ha detto che .NET Framework è affamato di memoria e mi ha dato un esempio che se faccio un'applicazione (in moduli Web .NET) che richiederà 20 MB di RAM, in realtà sarà sprecare 1.5 MB

Ciò significa che perde 15 mb per un'applicazione da 200 MB, il che è troppo.

È vero? Qualcuno può fornirmi dei collegamenti che lo descrivono?

    
posta Shaheer 05.06.2011 - 17:14
fonte

3 risposte

13

.net utilizza un heap gestito che esiste in congiunzione con le funzioni di memoria os incorporate in Windows. Mentre il costo iniziale di avvio del runtime può far sembrare il sistema molto ricco di memoria per i programmi su larga scala, ho trovato che non è così significativo. È necessario ricordare che l'accesso alla memoria gestita viene testato ogni anno da migliaia di sviluppatori e, in media, riuscirà a gestire al meglio la gestione della memoria per qualsiasi programma di portata significativa.

    
risposta data 05.06.2011 - 17:22
fonte
6

Dubito che ci sia davvero una risposta diretta a questo.

Ci sono due problemi da considerare. Innanzitutto, con la garbage collection, generalmente ottieni un compromesso abbastanza diretto tra la velocità e il consumo di memoria. Se si esegue il Garbage Collector più spesso, si riduce il consumo di memoria a scapito dell'utilizzo di più tempo della CPU. Esecuzione del garbage collector meno spesso migliora la velocità a spese di consumare più memoria. Test ha dimostrato che la raccolta dei dati inutili può fornire la stessa velocità della gestione manuale della memoria, a la spesa di consumare circa sei volte più memoria 1 .

Il secondo punto di base è la generalità contro la specificità. Da un lato, le persone che lavorano su .NET sono (senza ombra di dubbio) molto intelligenti e lavorano molto duramente per farlo funzionare bene. Per la maggior parte, ci riescono. D'altra parte, .NET viene utilizzato per una vasta gamma di scopi su una gamma ancora più ampia di hardware. Ciò ha un grande effetto sull'obiettivo di progettazione. In particolare, l'enfasi è quasi del tutto per evitare prestazioni davvero cattive in qualsiasi condizione, non necessariamente per fornire grandi prestazioni in tue condizioni.

Per quanto riguarda l'accusa specifica di 20 MB che porta a 1,5 MB di "spreco", dubito che qualcuno possa davvero affrontarlo direttamente - è impossibile essere sicuri di ciò che stava cercando di dire, per non parlare del tentativo di dire qualcosa sul fatto (e se a quale livello e / o in quali circostanze) potrebbe essere accurato. È certamente non vero che l'utilizzo della memoria è necessariamente lineare, quindi anche se 20 MB di utilizzo portano a 1,5 MB di rifiuti, ciò non implicherebbe 15 MB di rifiuti per 200 MB di utilizzo. A seconda di cosa stava parlando, potrebbe rimanere a 1,5 MB a prescindere, o potrebbe scalare in modo sub-lineare (o, possibilmente, in modo super-lineare).

1 Quei test specifici sono stati eseguiti con Java, ma .NET è sufficientemente simile che mentre il numero potrebbe cambiare un piccolo , non mi aspetto che la differenza sia enorme. Del resto, conosco almeno tre diversi metodi di raccolta dei dati inutili usati in JVM differenti, quindi il numero esatto probabilmente varia per le diverse implementazioni Java.

    
risposta data 05.06.2011 - 20:50
fonte
2

Sebbene la maggior parte della mia esperienza sia con la programmazione non GC, non credo che GC o non GC siano universalmente superiori.

Ciò che dirò, tuttavia, è che i sovraccarichi della memoria commerciale per la velocità o per altre risorse sono abbastanza comuni, anche per i linguaggi non GC.

Alcuni esempi ...

Un array ingenuo di dimensioni ridimensionabili cresce con incrementi fissi. Quando si inserisce un numero elevato di elementi, questo si traduce in prestazioni O (n ^ 2) a causa delle operazioni di riallocazione e copia sull'array O (n). Un'alternativa più veloce è il "raddoppiamento dell'array" - più precisamente, crescendo di un fattore fisso. Ciò fornisce prestazioni O (n) ammortizzate per una lunga sequenza di inserti. Il costo è che, invece di avere un overhead di memoria massimo fisso, il sovraccarico massimo è proporzionale al numero di elementi nell'array.

EDIT - errore stupido sopra - array fornisce O (1) per ogni inserto, ma rigorosamente O (n) per una serie di n inserimenti, a causa di come "ammortizzato" è definito.

Il raddoppiamento delle matrici non si applica solo a tipi vettoriali / array ridimensionabili semplici, ma anche a tipi con matrici resettabili sottostanti - le più ovvie sono le tabelle hash. Senza questo overhead di memoria proporzionale, non è possibile ottenere i tempi di inserimento / eliminazione ammortizzati di O (1) per hash ridimensionabili. Ciò vale indipendentemente dal fatto che venga utilizzata la garbage collection.

Allo stesso modo, con alberi B e alberi B + (comunemente usati per gli indici del database), ogni nodo è garantito almeno per metà - con l'eccezione della radice, che può anche essere completamente vuota. Queste strutture di dati sono più probabilmente utilizzate sul disco che nella memoria principale, ma in entrambi i casi hanno un sovraccarico di memoria / storage previsto che cresce in proporzione al numero di articoli.

Con algoritmi di garbage collection, ci sono anche compromessi tra memoria e prestazioni. In alcuni casi questo può essere visto come un ulteriore livello in cima alle strutture dati, aggiungendo uno strato aggiuntivo di rifiuti, ma questa non è una regola generale - non so quale peso pesare su ciascun caso.

Nelle lingue non gestite, è necessario un altro meccanismo per tenere traccia della memoria che deve essere comunque liberata. A volte, questo è praticamente gratis nella struttura dati stessa - ad es. in un albero binario, sono necessari i collegamenti secondari indipendentemente dal fatto che vengano utilizzati per un'operazione di eliminazione di tutti gli elementi o meno. Ma altre volte anche questo può comportare un compromesso tra overhead e prestazioni extra della memoria. Ad esempio, i "pool di memoria" vengono spesso utilizzati per scambiare i costi generali della memoria (l'intero pool rimane allocato, anche se relativamente pochi articoli all'interno del pool sono in uso in un determinato momento) per una più veloce e più conveniente libera da tutti gli elementi contemporaneamente.

Il mio punto di partenza è, immagino, una variazione su "evitare l'ottimizzazione prematura". Non preoccuparti troppo dei sovraccarichi di memoria se non sai che causeranno un problema. E sappi che quando si riducono le spese generali di memoria, è probabile che si paghi con aumenti ad altre spese generali, quindi fare prima e dopo le misurazioni di più di un semplice utilizzo della memoria.

Potrebbe sembrare che sia troppo tardi per pensare al cambio di lingua quando si riscontra un problema con i sovraccarichi della memoria di garbage collection, ma ci sono cose che si possono fare senza riscrivere l'intero sistema. Ad esempio, quando si codifica in C # per .NET, un'opzione è di reimplementare una struttura di dati critica utilizzando un C ++ non gestito.

    
risposta data 06.06.2011 - 00:49
fonte

Leggi altre domande sui tag