Autor |
Beitrag |
doubleII
Beiträge: 52
|
Verfasst: Mi 01.03.17 12:31
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!!!!!
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
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.
|
|
Th69
Beiträge: 4777
Erhaltene Danke: 1054
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Mi 01.03.17 14:57
Das scheint nicht mit .NET zu tun zu haben, sondern mit der von dir verwendeten Library FreeImage.
Ich tippe darauf, daß du eine Methode wie FreeImage.FreeHbitmap aufrufen mußt.
Sind denn dort keine Beispielprogramme dabei?
Laut FreeImage - Download:
Zitat: | FreeImage.Net C# distribution
This new wrapper was built up using C# and covers all features of FreeImage plus easy interaction with the .NET framework including .NET bitmaps, .NET colors and .NET streams. The wrapper comes with a couple of sample projects included as well as a Visual Studio like Microsoft Compiled HTML Help File.
|
|
|
doubleII
Beiträge: 52
|
Verfasst: 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.
|
|
doubleII
Beiträge: 52
|
Verfasst: Mi 01.03.17 17:12
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: 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
Beiträge: 52
|
Verfasst: 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?
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?
und ich verstehe immer noch nicht, warum immer noch Speicher frisst.
|
|
Th69
Beiträge: 4777
Erhaltene Danke: 1054
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: 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
Beiträge: 52
|
Verfasst: 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
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); } } |
Anweisung? Jetzt habe ich wirklich keine Ahnung was ich als nächstes machen muss.
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: 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.
Zuletzt bearbeitet von Ralf Jansen am Do 02.03.17 13:21, insgesamt 1-mal bearbeitet
|
|
Th69
Beiträge: 4777
Erhaltene Danke: 1054
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Do 02.03.17 13:11
Hast du dir jetzt mal die Beispielprogramme dazu angeschaut oder näher in die Doku?
Zum einen gibt es den Parameter 'unload' bei GetHbitmap und zum anderen die expliziten Methoden Unload bzw. UnloadEx.
|
|
doubleII
Beiträge: 52
|
Verfasst: 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
Beiträge: 52
|
Verfasst: 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.
|
|
Th69
Beiträge: 4777
Erhaltene Danke: 1054
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Fr 03.03.17 19:14
Das habe ich doch oben geschrieben.
|
|
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Fr 03.03.17 21:08
- Nachträglich durch die Entwickler-Ecke gelöscht -
|
|
doubleII
Beiträge: 52
|
Verfasst: Do 09.03.17 10:10
stimmt Th69 beim schreiben habe es übersehen.
Danke
|
|