Sto utilizzando bitmap bloccate molto recentemente e continuo a ricevere errori di "tentativo di accedere a memoria non valida". Questo è principalmente dovuto al fatto che la bitmap è stata spostata in memoria. Alcune persone usano GCHandle.Alloc()
per allocare memoria nel CLR e collegarlo. Bitmap.LockBits()
fa lo stesso? Non capisco la differenza tra "bloccare" la memoria e "bloccare" la memoria. Puoi spiegare anche la terminologia e le eventuali differenze?Bitmap.LockBits "pin" un bitmap in memoria?
risposta
GCHandle.Alloc
è un metodo più generico che consente di assegnare un handle a qualsiasi oggetto gestito e inserirlo nella memoria (o meno). Il blocco della memoria impedisce a GC di spostarlo, il che è particolarmente utile quando devi passare alcuni dati, ad esempio un array, a un codice non gestito.
GCHandle.Alloc
non consente di accedere ai dati della bitmap in alcun modo, poiché il blocco di questo oggetto impedisce semplicemente all'oggetto gestito di spostarsi (l'oggetto Bitmap) (e di essere raccolto inutilmente).
Bitmap tuttavia è un wrapper attorno alla struttura BITMAP
nativa di GDI +. Non conserva i dati in qualsiasi array gestito che si dovrebbe bloccare, ma ha appena gestito un handle nativo per l'oggetto bitmap GDI +. Per questo motivo, Bitmap.LockBits
è un modo per dire a questa bitmap che sei interessato ad accedere alla memoria, ed è solo un wrapper attorno alla funzione GdipBitmapLockBits
. Quindi il tuo bisogno di chiamarlo ha più a che fare con il fatto che stai lavorando con bitmap GDI + piuttosto che con il fatto che lavori in ambiente gestito con GC.
Una volta utilizzato LockBits
si dovrebbe essere in grado di accedere alla memoria tramite puntatori tramite BitmapData.Scan0
- è un indirizzo del primo byte di dati. Non dovresti avere problemi finché non accedi alla memoria dietro BitmapData.Scan0 + Height * Stride
.
E ricorda allo UnlockBits
quando hai finito.
Nel tuo caso un errore attempted to access invalid memory
è probabilmente causato da un'allocazione di memoria non valida che si sta facendo nella parte non sicura del codice, ad esempio l'array assegnato è inferiore al numero di pixel che si sta tentando di inserire.
Non è inoltre necessario pensare di bloccare gli oggetti a meno che i dati dell'immagine non siano less than 85000 Bytes poiché nella memoria verranno spostati solo oggetti inferiori a 85 K.
Un'altra storia sarebbe se si passasse l'oggetto al codice non gestito, ad esempio nella libreria C++ per un'elaborazione più rapida. In questo caso la tua eccezione è molto probabile se l'immagine passata esce dall'ambito e sarà raccolta dalla spazzatura. In questo caso puoi usare GCHandle.Alloc(imageArray,GCHandleType.Pinned);
e chiamare Free se non ne hai più bisogno.
La parte relativa all'heap di oggetti di grandi dimensioni e agli oggetti superiori a 85k è un'aringa rossa e peggiora questa risposta. Anche la raccomandazione di usare 'GCHandle.Alloc' su un puntatore non va bene. –
@BenVoigt L'ho spento due volte e non vedo perché è falso rosso o non è buono. Con questa risposta ho condiviso la mia esperienza che ho avuto nel mio caso simile http://stackoverflow.com/questions/14735520/ (leggi anche commenti). Quindi per favore spiega le tue parole. – VladL
Questa domanda riguarda il puntatore 'BitmapData.Scan0' ottenuto da' Bitmap.LockBits() '. 'Bitmap' non funzionerà se i dati vengono spostati, quindi non c'è alcun motivo per il chiamante' LockBits() 'per provare a bloccare i dati. E se il buffer è controllato da 'Bitmap', che è il solito caso, non viene assegnato dall'heap GC, quindi non è né sull'heap generazionale né sull'heap di oggetti di grandi dimensioni. –
stai usando il codice non sicuro per manipolare la bitmap dopo il blocco? – VladL
Sì, sto usando un codice non sicuro. –