C Gestione della memoria #: parola chiave non sicuri e puntatori
-
21-09-2019 - |
Domanda
Quali sono le conseguenze (positivo / negativo) di utilizzare il non sicuri parola chiave nel C # per usare puntatori? Per esempio, che diventa di raccolta dei rifiuti, quali sono le prestazioni utili / perdite, quali sono i guadagni di prestazioni / perdite rispetto ad altre lingue gestione manuale della memoria, quali sono i pericoli, in quale situazione è davvero giustificabile a fare uso di questa lingua caratteristica, è più lungo per compilare ...?
Soluzione
Come già detto da Conrad, ci sono alcune situazioni in cui l'accesso non sicuro alla memoria in C # è utile. Non ci sono come molti di loro, ma ci sono alcuni:
-
Manipolazione con
Bitmap
è quasi un tipico esempio in cui avete bisogno di qualche prestazioni aggiuntive che è possibile ottenere utilizzandounsafe
. -
Interoperabilità con API più anziani (come WinAPI o nativo C / C ++ DLL) è un'altra area dove
unsafe
può essere molto utile - ad esempio, si consiglia di chiamare una funzione che prende / restituisce un puntatore non gestito.
D'altra parte, si può scrivere la maggior parte delle cose utilizzando classe Marshall
, che nasconde molte delle operazioni non sicure all'interno chiamate di metodo. Questo sarà un po 'più lento, ma è un'opzione se si vuole evitare di utilizzare unsafe
(o se si sta utilizzando VB.NET che non ha unsafe
)
conseguenze positive :
Così, le principali conseguenze positive della esistenza di unsafe
in C # è che si può scrivere del codice più facilmente (interoperabilità) e si può scrivere del codice in modo più efficiente (con la manipolazione di bitmap o forse alcuni calcoli numerici pesanti utilizzo di matrici - anche se, I' m non così sicuro circa il secondo).
Conseguenze negative : Certo, c'è qualche prezzo che si deve pagare per l'utilizzo di unsafe
:
-
codice non verificabile : codice C # che è scritto utilizzando le funzionalità
unsafe
diventa non verificabile, che significa che il vostro codice potrebbe compromettere il runtime in alcun modo. Questo non è un grosso problema in un pieno di fiducia scenario (ad esempio senza restrizioni un'applicazione desktop) - semplicemente non si dispone di tutte le belle garanzie .NET CLR. Tuttavia, non è possibile eseguire l'applicazione in un ambiente ricercato ristretto come ad esempio l'hosting web pubblico, Silverlight o attendibilità parziale (ad esempio, un'applicazione in esecuzione dalla rete). -
Garbage collector ha anche bisogno di fare attenzione quando si utilizza
unsafe
. GC è di solito permesso di riposizionare gli oggetti sul heap gestito (per mantenere la memoria deframmentato). Quando si prende un puntatore ad un oggetto, è necessario utilizzare la parola chiavefixed
a dire il GC che non può spostare l'oggetto fino al completamento (che probabilmente potrebbe influire sulle prestazioni di raccolta dei rifiuti - ma, naturalmente, a seconda dello scenario esatto) .
La mia ipotesi che, se C # non ha dovuto interagire con il codice più vecchio, probabilmente sarebbe non supporta unsafe
(progetti di ricerca e come Singularity che tentano di creare il sistema operativo più verificabile sulla base di lingue gestite sicuramente non permettere il codice usnsafe). Tuttavia, nel mondo reale, unsafe
è utile in alcuni (rari) casi.
Altri suggerimenti
Posso darvi una situazione in cui valeva la pena utilizzando:
Devo generare un pixel per pixel bitmap. Drawing.Bitmap.SetPixel()
è troppo lento. Così ho costruire la mia Array
gestito dei dati bitmap, e utilizzare unsafe
per ottenere il IntPtr
per Bitmap.Bitmap( Int32, Int32, Int32, PixelFormat, IntPtr)
.
Per citare professionale C # 2008:
"Le due ragioni principali per l'utilizzo puntatori sono:
- compability indietro - Nonostante tutte le agevolazioni previste dal NET-runtime è ancora possibile chiamare funzioni API di Windows native, e per alcune operazioni puo essere unico modo per accompling il vostro compito. Queste funzioni API sono generalmente scritto in C e spesso richiedono puntatori come parametri. Tuttavia, in molti casi è possibile scrivere il Dichiarazione DllImport in un modo che evita l'uso di puntatori; per esempio, utilizzando la classe System.IntPtr.
- Performance - In quelle occasioni in cui la velocità è di fondamentale importanza, puntatore può fornire una rotta verso perfomance ottimizzato. Se tu sa cosa si sta facendo, si può assicurare che i dati si accede o manipolato nel modo più efficiente. Tuttavia, essere consapevoli del fatto che, il più delle volte che no, ci sono altre aree di codice in cui è possibile effettuare necessaria improvemens prestazioni senza resoirting ai puntatori. Provare a usare un profiler del codice a cercare i colli di bottiglia nel codice - si arriva con Visual Studio 2008 ".
E se si utilizza il codice di puntatore richiederà più alto la leva di fiducia da eseguire e se l'utente non concede che il codice non verrà eseguito.
E avvolgetelo con un ultima citazione:
"Siamo fortemente consiglio contro l'uso puntatori inutilmente perché sarà non solo essere più difficile di scrivere ed eseguire il debug, ma sarà anche fallire la memoria controlli tipo di sicurezza imposte dalla CLR ".
Garbage Collection è inefficiente con oggetti longevi. garbage collector di Net funziona meglio quando la maggior parte degli oggetti vengono rilasciati piuttosto rapidamente, e alcuni oggetti "vivere per sempre". Il problema è che gli oggetti più lunghi vivente vengono rilasciati solo durante garbage collection completa, che incorre in una penalità di prestazioni significative. In sostanza, gli oggetti di lunga vita si muovono rapidamente in generazione 2.
(Per ulteriori informazioni, si potrebbe desiderare di leggere su generazionale garbage collector di .Net: http://msdn.microsoft.com/en-us/library/ms973837.aspx )
In situazioni in cui oggetti, o l'uso della memoria in generale, sta per essere longeva, gestione manuale della memoria produrrà migliori prestazioni, perché può essere rilasciato per il sistema senza richiedere una garbage collection completa.
L'implementazione qualche tipo di un sistema di gestione della memoria basata su un unico grande array di byte, le strutture, e un sacco di aritmetica dei puntatori, potrebbe teoricamente aumentare le prestazioni in situazioni in cui i dati saranno memorizzati in RAM per un lungo periodo di tempo.
Purtroppo, io non sono a conoscenza di un buon modo per farlo gestione manuale della memoria in .Net per gli oggetti che stanno per essere longeva. Ciò significa che le applicazioni che hanno i dati di lunga durata nella RAM saranno periodicamente non rispondere quando corrono una garbage collection completa di tutta la memoria.