2015-08-08 9 views
6

System.Runtime.Caching.MemoryCache è una classe in .NET Framework (versione 4+) che memorizza nella memoria oggetti, utilizzando stringhe come chiavi. Più di System.Collections.Generic.Dictionary<string, object>, questa classe ha tutti i tipi di campane e fischietti che ti permettono di configurare a quanto può essere estesa la cache (in termini assoluti o relativi), impostare diverse politiche di scadenza per diversi elementi della cache e molto altro ancora.Cosa significano esattamente i limiti di memoria di MemoryCache?

Le mie domande riguardano i limiti di memoria. Nessuno dei documenti su MSDN sembra spiegare questo in modo soddisfacente, e il codice sulla fonte di riferimento è piuttosto opaco. Mi dispiace di aver accumulato tutto questo in una "domanda" SO, ma non riesco a capire come prenderne un po 'nelle loro domande, perché in realtà sono solo visioni diverse di una domanda generale: "come si concilia l'idioma C#? /.NET con la nozione di una cache in-memory generalmente utile che ha limiti di memoria configurabili implementati quasi interamente nel codice gestito? "

  1. Le dimensioni delle chiavi contano rispetto allo spazio occupato da MemoryCache? Per quanto riguarda le chiavi nel pool interno, ciascuna delle quali dovrebbe solo aggiungere la dimensione di un riferimento a un oggetto alla dimensione della cache?
  2. MemoryCache considera oltre le dimensioni dei riferimenti oggetto che memorizza quando determina la dimensione dell'oggetto che viene archiviato nel pool? Voglio dire ... deve, giusto? Altrimenti, le opzioni di configurazione sono estremamente fuorvianti per il caso comune ... per le restanti domande, assumerò che lo faccia.
  3. Dato che MemoryCache considera quasi certamente la dimensione dei riferimenti agli oggetti dei valori memorizzati nella cache, quanto è profondo?
    1. Se mi stavano attuando qualcosa di simile, mi troverei molto difficile da prendere in considerazione l'utilizzo della memoria dei componenti "figli" dei singoli oggetti, senza tirare anche nelle proprietà di riferimento "madre".
    2. ad esempio, immaginare una classe in un'applicazione di gioco, Player. Player ha uno stato specifico per giocatore che è incapsulato in una proprietà public PlayerStateData PlayerState { get; } che incapsula la direzione del giocatore, quanti pignoni reggono, ecc., Nonché un riferimento all'intero stato del gioco public GameStateData GameState { get; } che può essere utilizzato per ottenere ritorno allo stato (molto più grande) del gioco da un metodo che conosce solo un giocatore.
    3. MemoryCache considera sia PlayerState sia GameState quando si considera la dimensione del contributo alla cache?
    4. Forse è più come "qual è la dimensione totale nell'heap gestito occupato dagli oggetti direttamente memorizzati nella cache e tutto ciò che è raggiungibile attraverso i membri di tali oggetti"?
    5. Sembra che sarebbe stupido moltiplicare le dimensioni del contributo di GameState al limite di 5 solo perché 5 giocatori sono memorizzati nella cache ... ma poi di nuovo, una probabile implementazione potrebbe fare proprio questo, ed è difficile contare PlayerState senza contare GameState.
  4. Se un oggetto viene memorizzato più volte nella MemoryCache, ciascuna voce viene conteggiata separatamente rispetto al limite?
  5. Relativo al precedente, se un oggetto è memorizzato direttamente nel MemoryCache, ma anche indirettamente attraverso i membri di un altro oggetto, quale impatto ha uno sul limite di memoria?
  6. Se un oggetto è memorizzato nel MemoryCache, ma viene anche referenziato da alcuni altri oggetti live completamente disconnessi dalla MemoryCache, quali oggetti contano rispetto al limite di memoria? Che dire se si tratta di una matrice di oggetti, alcuni (ma non tutti) di cui hanno riferimenti esterni in entrata?

La mia ricerca mi ha portato a SRef.cs, che ho rinunciato a cercare di capire dopo aver ottenuto here, che poi conduce here. Indovinare le risposte a tutte queste domande ruoterebbe attorno alla ricerca e alla meditazione sul codice che alla fine ha popolato l'INT64 che è memorizzato in quella maniglia.

+0

IMO l'implementazione più utile della gestione dei limiti di MemoryCache implicherebbe che la cache sia in grado di rispondere perfettamente alla domanda, "se venissi cancellato e un GC completo fosse eseguito immediatamente dopo, quanti byte di memoria verrebbero liberati durante quella esecuzione di GC ?" Ma più penso a questo, più mi aspetto che la sua risposta sia pesantemente gonfiata se il proprietario della cache non rispetta un certo insieme di regole non rivelate (o almeno non scoperte), quindi questo è rilevante per più di un semplice ragioni teoriche –

+0

Sono venuto qui chiedendo esattamente le stesse domande, in particolare per quanto riguarda i riferimenti allo stato condiviso. Un'altra domanda mi affligge anche ... supponendo che il tuo oggetto memorizzato nella cache (grafico) cresca o si ritiri dopo che è stato inserito nella cache ...? È tutto piuttosto vago. – spender

risposta

1

So che è tardi, ma ho cercato molto nel codice sorgente per cercare di capire cosa sta succedendo e ora ho un'idea abbastanza buona. Dirò che MemoryCache è la peggiore classe documentata su MSDN, il che mi sconcerta per qualcosa destinato a essere usato da persone che cercano di ottimizzare le loro applicazioni.

MemoryCache utilizza uno "riferimento di dimensioni" speciale per misurare la dimensione degli oggetti. Sembra tutto un hack gigante nel codice sorgente della cache di memoria che coinvolge la riflessione per avvolgere un tipo interno chiamato "System.SizedReference", che da quello che posso dire fa sì che il GC imposti la dimensione del grafo oggetto a cui punta durante gen 2 collezioni.

Dal mio test, questo includerà le dimensioni degli oggetti genitore, e quindi tutti gli oggetti figlio a cui fa riferimento il genitore, ecc, ma ho scoperto che se si fanno riferimenti a oggetti genitore riferimenti deboli (cioè tramite WeakReference o WeakReference<>) quindi non è più conteggiato come parte del grafico dell'oggetto, quindi è quello che faccio per tutti gli oggetti cache ora.

Credo che gli oggetti cache debbano essere completamente autosufficienti o utilizzare riferimenti deboli ad altri oggetti affinché il limite di memoria funzioni.

Se si desidera giocare da soli, è sufficiente copiare il codice da SRef.cs, creare un grafico oggetto e puntare una nuova istanza SRef su di esso, quindi chiamare GC.Collect. Dopo la raccolta, le dimensioni approssimative saranno impostate sulla dimensione del grafico dell'oggetto.