Entwickler-Ecke
Sonstiges (.NET) - Speicher freigeben bei FreeImage-Library
doubleII - Mi 01.03.17 12:31
Titel: Speicher freigeben bei FreeImage-Library
Hallo zusammen,
ich habe folgendes Problem:
Auf einer Oberfläche habe ich drei Kameras, wenn ich die Bilder auswerten möchte, wird die Execute Funktion
aufgerufen. Sie ist eine un-verwaltete Funktion
C#-Quelltext
1: 2: 3: 4:
| [DllImport(@"C:\Program Files (x86)\AS\Runtime\Toolbox.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Execute")] public static extern int Execute(int count, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] bitmaps); |
Deklaration
C#-Quelltext
1: 2: 3: 4: 5: 6: 7:
| private Bitmap[] _bmp = new Bitmap[3]; private IntPtr[] _bmpScorpion = new HBITMAP[3]; private IntPtr _bm = HBITMAP.Zero; private string _tag= ""; private int _camCount = 0; private FIBITMAP _fibitmaps = FIBITMAP.Zero; private bool disposedValue = false; |
hier der Constructor
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| public ScorpionFunctions(Bitmap bmp1, Bitmap bmp2, Bitmap bmp3, int cameraCount) { this._camCount = cameraCount; this._bmp = new Bitmap[3]; this._bmpScorpion = new HBITMAP[3]; this._bmp[0] = bmp1; this._bmp[1] = bmp2; this._bmp[2] = bmp3; this._bm = HBITMAP.Zero; } |
der Aufruf der Funktion
C#-Quelltext
1: 2: 3: 4: 5: 6:
| using (var obj = new ScorpionFunctions(_bmp1, _bmp2, _bmp3, _camCount)) { Action<CallBackSvbFunction> delegateObj = obj.SvbExecute; delegateObj.Invoke(CallBackInt); } |
hier muss ich bitpam in hbitmap ptr konvertieren. Ich habe fibitmap genommen, da fibitmap vesentlich schneller ist.
Falls ich die if(bmp[0]) eins und zwei Teile auskommentiere wächst der Speicher nicht!!!!!
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| public void SvbExecute(CallBackSvbFunction @return) { int hresult = 0; bool unload = false; if (_bmp[0] != null) { _fibitmaps = FreeImage.CreateFromBitmap(_bmp[0]); _bmpScorpion[0] = FreeImage.GetHbitmap(_fibitmaps, _bm, unload); } if (_bmp[1] != null) { _fibitmaps = FreeImage.CreateFromBitmap(_bmp[1]); _bmpScorpion[1] = FreeImage.GetHbitmap(_fibitmaps, _bm, unload); } if (_bmp[2] != null) { _fibitmaps = FreeImage.CreateFromBitmap(_bmp[2]); _bmpScorpion[2] = FreeImage.GetHbitmap(_fibitmaps, _bm, unload); }
try { int count = _bmpScorpion.Length; @return(SvbFunctionLibrary.Execute(count, _bmpScorpion)); }
catch (Exception ex) { MessageBox.Show(ex.Message, ex.StackTrace); } } |
und zum Schluss will ich alles freigeben
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44:
| protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { _bmp[0]?.Dispose(); _bmp[0] = null; _bmp[1]?.Dispose(); _bmp[1] = null; _bmp[2]?.Dispose(); _bmp[2] = null; _bm = IntPtr.Zero; }
_bmpScorpion[0] = IntPtr.Zero; _bmpScorpion[1] = IntPtr.Zero; _bmpScorpion[2] = IntPtr.Zero; _fibitmaps = FIBITMAP.Zero; disposedValue = true; } } ~ScorpionFunctions() { Dispose(false); }
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } |
trotzdem wächst der Speicher und das Programm stürzt nach einer Zeit ab.
Weißt jemand, wo ich einen Fehler mache, da ich den nicht finde?
:(
Danke!
Moderiert von
Th69: Topic aus WinForms verschoben am Mi 01.03.2017 um 13:58
Moderiert von
Th69: Titel geändert.
doubleII - Mi 01.03.17 15:12
Ja habe mir auch gedacht und habe ohne die FreeImage.GetHbitmap probiert.
Ich habe die Library verwendet:
C#-Quelltext
1: 2: 3: 4:
| using System.Drawing; HBITMAP = System.IntPtr;
HBITMAP hbitmap = bmp[0].GetHbitmap(); |
wieder das gleiche.
:shock:
doubleII - Mi 01.03.17 17:12
verstehe nicht. Ich rufe jetzt die class FreeImageBitmap auf. Sie hat ein destructor
C#-Quelltext
1: 2: 3: 4:
| using (FreeImageBitmap obj = new FreeImageBitmap(_bmp[0])) { _bmpScorpion[0] = obj.GetHbitmap(); } |
und noch dazu für die class ScorpionFunctions habe dispose Methode. Es frisst jetzt doppel so wenig aber trotzdem frisst. Woran kann es noch liegen?
:shock: :shock: :shock:
Ralf Jansen - Mi 01.03.17 19:32
Zitat: |
verstehe nicht. Ich rufe jetzt die class FreeImageBitmap auf. Sie hat ein destructor |
Wenn _bmpScorpion weiterhin Pointer auf GDI objekte enthält mußt du die explicit freigeben. Ich bezweifle das FreeImageBitmap sich dafür zuständig fühlt nachdem du es per GetHbitmap da raus geholt hast.
Und wenn doch macht die die Aufräumarbeiten sicher in Dispose und nicht im Destruktor.
Aber das solltest du leicht rausfinden können. Funktioniert in deinem letzten Code _bmpScorpion[0] nach dem Ende des using Blocks noch? Dann bist definitiv du für das zerstören verantwortlich und nicht die FreeImageBitmap Klasse.
Moderiert von
Th69: URL- durch Quote-Tags ersetzt
doubleII - Do 02.03.17 09:22
Zitat: |
Und wenn doch macht die die Aufräumarbeiten sicher in Dispose und nicht im Destruktor. |
Hi Ralf, ja stimmt du hast voller Recht nach dem using ausgeführt wird landet in der Dispose, also ich rufe explizit die Methode.
Es ist doch das selbe, ob ich Dispose aufrufe oder der Destrunktor, nicht war?
Zitat: |
Funktioniert in deinem letzten Code _bmpScorpion[0] nach dem Ende des using Blocks noch? |
Ja, es funktioniert, da ich die _bmpScorpion[0] zwei und drei an der Execute weiter als Parameter übergebe und sehe das Ergebnis.
Zitat: |
Dann bist definitiv du für das zerstören verantwortlich und nicht die FreeImageBitmap Klasse.
|
Was meinst damit? Es wird doch Dispose aus der FreeImageBitamp aufgerufen. Wenn ich Beispiel using nicht verwende, wird der Destruktor am Ende aufgerufen? :roll:
also wenn ich den Code so auskommentiere:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7:
| if (_bmp[0] != null) { FreeImageBitmap obj = new FreeImageBitmap(_bmp[0]); obj.Dispose(); |
das Programm frisst keinen Speicher, also das heißt, dass die FreeImageBitmap den Speicher freigibt.
Was ist mit dem IntPtr?
wenn ich IntPtr freigeben möchte reicht es, wenn ich den IntPtr auf null setze?
C#-Quelltext
1: 2: 3:
| _bmpScorpion[0] = IntPtr.Zero; _bmpScorpion[1] = IntPtr.Zero; _bmpScorpion[2] = IntPtr.Zero; |
wie ich oben in der Dispose Methode geschrieben habe. Wird der Speicher so freigegeben? :shock: :shock: :shock:
und ich verstehe immer noch nicht, warum immer noch Speicher frisst. :les: :les: :les:
Th69 - Do 02.03.17 11:56
Es geht um den Speicher der von der nativen FreeImage-Lib reserviert wurde.
Da kannst du noch so sehr das .NET Bitmap freigeben, das reicht nicht. Du mußt anscheinend auch noch die zugehörige FIBITMAP freigeben.
doubleII - Do 02.03.17 12:25
Hallo Th69, ich habe noch dazu geschrieben, wenn ich nur die FreeImageBitmap Klasse aufrufe, frisst keinen Speicher mehr. Hast du gelesen?
from FreeImageBitmap
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73:
| protected virtual void Dispose(bool disposing) { lock (lockObject) { if (disposed) { return; } disposed = true; }
if (disposing) { if (stream != null) { if (disposeStream) { stream.Dispose(); } stream = null; } }
tag = null; saveInformation = null;
UnloadDib(); }
private bool ReplaceDib(FIBITMAP newDib) { bool result = false; if ((dib != newDib) && (!newDib.IsNull)) { UnloadDib(); dib = newDib; AddMemoryPressure(); result = true; } return result; }
private void UnloadDib() { if (!dib.IsNull) { long size = FreeImage.GetDIBSize(dib); FreeImage.UnloadEx(ref dib); if (size > 0L) GC.RemoveMemoryPressure(size); } } |
:shock: :shock: :shock:
Anweisung? Jetzt habe ich wirklich keine Ahnung was ich als nächstes machen muss.
Ralf Jansen - Do 02.03.17 12:52
Zitat: |
Es ist doch das selbe, ob ich Dispose aufrufe oder der Destrunktor, nicht war? |
Eigentlich nicht. Wenn du aus dem Destruktor Dispose aufrust kommt es irgendwann auf das gleiche heraus. Das irgendwann ist der Unterschied. Der Destruktor wird irgendwann aufgerufen, nicht explizit von dir, sondern vom Garbage Collector der halt irgendwann läuft. Nur über Dispose hast du Kontrolle wann nicht gemanagte Resourcen ferigegeben werden. Wenn Dispose denn alle nicht gemanagten REsourcen abdeckt. In deinem Fall tut es die Klasse offensichtlich nicht sondern der IntPtr den du dir geholt hast müßte nach dem Ende des usings auf ungültigen Speicher zeigen.
Zitat: |
_bmpScorpion[0] = IntPtr.Zero; |
Hier wird nichts freigegeben. Wenn man den Verweis auf eine .Net Resource entfernt würde es irgendwann freigegeben werden (wenn es das System für nötig halt nicht sofort). Das was du hinter dem HBITMAP verwaltest ist aber ein Windows Objekt das nicht von .NET verwaltet wird (es ist eine unmanaged Resource) und daher auch durch die normalen .NET Mechanismen nicht abgedeckt. Unmanged heißt du mußt es managen das es zerstört wird.
Das was
Th69 aus deiner 3th-Party Bibliothek verlinkt hat sieht so aus als wäre es etwas das die Freigabe des HBITMAP kapselt.
Zitat: |
Hallo Th69, ich habe noch dazu geschrieben, wenn ich nur die FreeImageBitmap Klasse aufrufe, frisst keinen Speicher mehr. Hast du gelesen? |
Solange du nur die .NET Oberfläche der Bibliothek benutzt ist das auch nachvollziehbar wenn die gut programmiert ist. Der Aufruf von GetHbitmap() (potentiel jede Funktion die einen IntPtr liefert) wird dir aber etwas geben das nicht gemanged ist da du quasi den .Net Raum verlässt. Da hört der Nanny Teil von .NET auf und deine Zuständigkeit fängt an.
doubleII - Fr 03.03.17 09:09
na ja Th69 die Methode habe ich am Anfang verwendet. Ich muss rausfinden, was ich falsch mache. Es schaut so aus, dass Heap zu verwalten ist nicht so easy.
Danke!
doubleII - Fr 03.03.17 11:40
für diejenige, die FreeImage nutzten werden. Es gibt eine Methode UnlodEx(ref FIBITMAP value). Die gibt der handle in der FIBITMAP struct frei. Wird die Methode nicht aufgerufen wird der Heap irgendwann voll.
:lol: :dance2:
Th69 - Fr 03.03.17 19:14
Das habe ich doch oben geschrieben. :gruebel:
Delete - Fr 03.03.17 21:08
- Nachträglich durch die Entwickler-Ecke gelöscht -
doubleII - Do 09.03.17 10:10
stimmt Th69 beim schreiben habe es übersehen. :D
Danke
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!