2009-10-08 13 views
5

Ho iniziato a scrivere una grande applicazione in C# per la prima volta nella mia vita. Ho scritto un modulo di esempio per testare l'idea alla base del mio software. Questo modulo conteneva diverse dozzine di dizionari C# e liste di oggetti che ciascuno aveva diversi membri e proprietà.Le applicazioni .NET sono naturalmente ad uso intensivo di memoria?

Sono rimasto scioccato dal fatto che, dopo aver inizializzato gli oggetti principali, abbia utilizzato circa 40 MB di RAM.

Ho provato e ho scoperto che più di 30 MB sono allocati dopo l'inizializzazione dell'oggetto, ma avevo l'impressione che data la dimensione dei miei oggetti, non si sarebbero dovute consumare più di qualche centinaio di kilobyte.

Ho fatto qualcosa di sbagliato o .NET è molto più ricco di memoria rispetto alle applicazioni di codice nativo?

+4

Il runtime è pesante. –

+2

Sono d'accordo con te. Penso che tu stia facendo qualcosa di terribilmente sbagliato. –

+0

Puoi pubblicare qualche codice di esempio?Penso che sarà di grande aiuto nel capire se è il codice che lo causa da solo o è aggravato dal tempo di esecuzione –

risposta

7

L'utilizzo di Task Manager per esaminare l'utilizzo della memoria è probabilmente inaccettabile.

Invece, afferrare un ricordo adeguato strumento di profiling (dotTrace è molto buona, e ha un 10 giorni di prova) e prendere il tempo di vedere il vostro attuale consumo di memoria.

il genere di cose che ho visto nel mio codice includono

  • Sottovalutare la quantità di memoria realtà sto usando (senza contare oggetti separati correttamente, non permettendo per le liste di avere la capacità "di riserva")
  • riferimenti tenendosi oggetti transitori che non ho bisogno
  • non permettere per gli oggetti transitori creati durante il funzionamento che non sono ancora stati garbage collection
  • non permettere per la memoria allocata - memoria che è stata rivendicata dal sistema operativo (e il refore viene mostrato come parte del processo in Task Manager) ma che non è stato assegnato a nessun oggetto ancora
  • Non consentendo stack di thread (ogni thread riceve uno stack proprio; Le applicazioni .NET sono sempre multi-threaded in quanto il framework può creare diversi thread.
2

Non si parla sempre del linguaggio, di solito si tratta di come viene utilizzato.

Il codice buono può utilizzare la memoria in modo efficiente in qualsiasi lingua.

codice Bad aumento dell'occupazione della memoria inefficiente in tutte le lingue

+4

Beh, solo a metà vero. La lingua/runtime in questo caso * fa * in effetti importa parecchio. -1 –

+1

Corretto, se ti importa qualche centinaio di K di memoria, C è spesso una scelta migliore. –

+1

Cosa non va della mia risposta? (aggiornato leggermente per enfatizzare) –

12

Come hai fatto a determinare la quantità di memoria che è stata utilizzata? È noto che le applicazioni .NET riservano con impazienza più memoria del necessario, a patto che ci sia abbondanza di memoria disponibile e rilascino la memoria sul sistema se inizia a esaurire la memoria.

Penso che potresti ottenere alcuni indicatori in this MSDN article.

+0

Utilizzando il task manager - grazie a indicare che non può essere un numero valido – PiotrK

2

Il runtime .Net ha un certo overhead di grandi dimensioni - abbiamo scoperto che anche le applicazioni più semplici tendono ad utilizzare molta più memoria che applicazioni simili scritte in C++. Fortunatamente questo overhead viene rapidamente disipiato dal rumore al crescere della dimensione del codice complessivo. Il secondo fattore è quello della garbage collection, il garbage collector viene eseguito "ogni volta", quindi rispetto al C++, le allocazioni di memoria non vengono in genere liberate subito, ma piuttosto quando si sente il requisito di farlo.

5

Nei giorni in cui abbiamo diversi GB di RAM su una macchina, l'idea che un'app rivolta all'utente come si farebbe in genere in C# dovrebbe utilizzare solo alcuni 100K di ram è all'indietro. Qualsiasi ram inutilizzata sul tuo sistema è sprecata.

Con questo in mente, C# alloca memoria utilizzando strategia molto diverso da C++, in modo che blocchi più grandi sono allocati e liberati meno spesso.

Detto questo, 40 sembra un po 'alto. Sono abituato a qualcosa di più vicino a 10-14Mb per applicazioni console molto semplici. Forse c'è un modulo che occupa ram, o forse sono su una versione diversa del framework (2.0).

+4

"Qualsiasi ram inutilizzato sul tuo sistema è sprecato." Qualsiasi RAM che la mia app non stia registrando può forse essere meglio utilizzata da un'altra app o dal sistema operativo. –

+2

Ma non viene 'hogged', viene assegnato dal runtime in modo avido. Il runtime può anche restituirlo al sistema operativo, se necessario. –

+0

uno dei motivi principali per cui Linux funziona meglio di Windows è perché utilizza tutta la memoria non utilizzata come cache del disco, migliorando notevolmente la velocità di lettura (che è molto necessaria a causa dell'idioma * nix dell'uso di file vuoti come flag). Se la tua app accarezza questa memoria, non può farlo. – rmeador

2

Direi che a meno che non si disponga di un molto buona ragione per preoccuparsi dell'utilizzo della RAM, non fare . Come le ottimizzazioni, devi solo ottimizzare dove c'è un cliente/utente finale che ha bisogno di farlo. Non credo gli utenti sono così costretti dalla memoria in questi giorni (a meno che non si sta parlando di un sistema embedded) che stanno andando a notare o preoccuparsi molto per la mancanza di un 38 MB.

+0

Se vedo 40 megas utilizzati dopo aver scritto un singolo modulo e l'applicazione avrà ... diciamo 20-30 moduli di questo tipo moltiplicano il set di dati completo di, beh - sono preoccupato che non lo farò in 512 megabyte di RAM – PiotrK

+1

@ PiotrK: Sì, se fosse così semplice, ma non lo è. Le applicazioni .NET sono gestite dal runtime. La quantità di memoria utilizzata non riflette direttamente ciò che stai facendo con il tuo codice, le tue ipotesi sono errate. –

+0

PiotrK: ma non lo farai. L'utilizzo della memoria non è scalabile in modo lineare con il numero o la dimensione dei moduli. Ottieni un grande successo per il runtime .NET, ma prendi quel colpo solo una volta. Potresti vedere che con un modulo stai consumando 40 MB, ma ogni modulo successivo potrebbe aggiungere solo un altro paio di MB (a seconda della quantità di memoria che viene allocata, ovviamente). – itowlson

-8

Facendo un calc rapido si sono probabilmente assegnano intorno 340K oggetti (sottraendo il solito colpo c12MB per le applicazioni console singoli su 32bit, yikes Steve!) E vedere [rimuovere il riferimento a un tipico scenario di mangiare 8bytes per oggetto + allora alcuni per altri soliti sospetti] di runtime e System.Object di rifiuti per i tipi di riferimento dal copyright razionale tech copyright @ Sun.com ..

Provare e progettare per tipi/strutture di valori se possibile ... se non è possibile, difficile dire agli utenti di non eseguire più di 10 app .NET o il loro computer si sentirà più lento del C64. Se ti fa sentire meglio, prova WPF o Silverlight e prova penalità di c100MB per alcuni pulsanti e animazioni appariscenti.

(sensazione downvote)

+2

Questo è un consiglio terribile e impreciso. -1 –

+4

Così male che devo dirlo due volte. –

+0

Certo, assicurati di passare al blog dei progettisti dei motori di esecuzione CLR e leggere le voci sul motivo per cui hanno optato per la tecnica del tipo valore, in realtà l'assegnazione dell'array in modo da evitare questo tipo di sovraccarico in 2 app che hanno realizzato dal 2001. Btw , in quella squadra, la maggior parte è stata fatta, scappata, moth madre di Google e continua a spianare la strada .. –

0

Se si utilizza Task Manager per esaminare la memoria che può essere fuorviante. Working Set è la quantità di memoria virtuale mappata al processo. Non necessariamente quanto l'applicazione sta usando - questo è particolarmente vero nell'ambiente garbage-collected di .NET. Poiché il programma assegna la memoria, .NET CLR/GC di solito richiede più memoria di quella effettivamente necessaria dal sistema operativo in modo che possa allocare in modo efficiente tale memoria agli oggetti gestiti nel programma in futuro.

Un modo rapido e sporco (molto sporco) per vedere se questo sta interessando voi è quello di impostare Process.MaxWorkingSet proprietà a 0. Questo è simile all'utilizzo SetProcessWorkingSetSize in Win32 per cercare di tagliare la quantità di pagine mappate al processo. Se vedi immediatamente un calo nell'utilizzo della memoria, allora sai cosa sta succedendo. Tuttavia, non appena si inizia ad allocare nuovamente la memoria tramite GC/CLR, verrà ripristinato, e solitamente questa è una buona cosa. Davvero non dovresti preoccuparti di questo e dare al GC la possibilità di farlo nel modo giusto.

Per entrambi ottimizzare l'utilizzo della memoria del vostro programma e ottenere una migliore idea di come funziona l'allocazione della memoria nel CLR Vi suggerisco di iniziare pasticciano con dotTrace (la mia preferenza), Ants Profiler (che tra l'altro publishes a cool video on this topic here). CLRProfiler è interessante, ma è un po 'datato in questi giorni, ma è gratuito.

Problemi correlati