Autor Beitrag
doubleII
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 52



BeitragVerfasst: 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

ausblenden 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
ausblenden 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// To detect redundant calls


hier der Constructor
ausblenden 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
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
using (var obj = new ScorpionFunctions(_bmp1, _bmp2, _bmp3, _camCount))
                    {
                        // used delegate
                        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!!!!!
ausblenden volle Höhe 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;
            //MessageBox.Show(" {0} " + GC.GetTotalMemory(true));
            if (_bmp[0] != null)
            {
                // create fibitmap from bitmap 
                _fibitmaps = FreeImage.CreateFromBitmap(_bmp[0]); // dauert ~ 5ms
                // creat hbitmap 
                _bmpScorpion[0] = FreeImage.GetHbitmap(_fibitmaps, _bm, unload);
            }
            if (_bmp[1] != null)
            {
                _fibitmaps = FreeImage.CreateFromBitmap(_bmp[1]); //dauert ~ 5 ms
                _bmpScorpion[1] = FreeImage.GetHbitmap(_fibitmaps, _bm, unload);
            }
            if (_bmp[2] != null)
            {
                _fibitmaps = FreeImage.CreateFromBitmap(_bmp[2]); //dauert ~ 5 ms
                _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
ausblenden volle Höhe 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)
                {
                    //// TODO: dispose managed state (managed objects).                   
                    _bmp[0]?.Dispose();
                    _bmp[0] = null;
                    _bmp[1]?.Dispose();
                    _bmp[1] = null;
                    _bmp[2]?.Dispose();
                    _bmp[2] = null;
                    _bm = IntPtr.Zero;
                }

                // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
                // TODO: set large fields to null.
                // TODO: dispose managed state (managed objects).
                      
                _bmpScorpion[0] = IntPtr.Zero;
                _bmpScorpion[1] = IntPtr.Zero;
                _bmpScorpion[2] = IntPtr.Zero;              
                _fibitmaps = FIBITMAP.Zero; 
                                
                disposedValue = true;
            }
        }
       
        // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
        ~ScorpionFunctions()
        {
            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
            Dispose(false);
        }

        // This code added to correctly implement the disposable pattern.
        public void Dispose()
        {
            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
            Dispose(true);
            // TODO: uncomment the following line if the finalizer is overridden above.
            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 user profile iconTh69: Topic aus WinForms verschoben am Mi 01.03.2017 um 13:58
Moderiert von user profile iconTh69: Titel geändert.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 52



BeitragVerfasst: Mi 01.03.17 15:12 
Ja habe mir auch gedacht und habe ohne die FreeImage.GetHbitmap probiert.
Ich habe die Library verwendet:

ausblenden C#-Quelltext
1:
2:
3:
4:
using System.Drawing;
HBITMAP = System.IntPtr;

HBITMAP hbitmap = bmp[0].GetHbitmap();


wieder das gleiche.

:shock:
doubleII Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 52



BeitragVerfasst: Mi 01.03.17 17:12 
verstehe nicht. Ich rufe jetzt die class FreeImageBitmap auf. Sie hat ein destructor
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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 user profile iconTh69: URL- durch Quote-Tags ersetzt
doubleII Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 52



BeitragVerfasst: 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:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
   if (_bmp[0] != null)
            {
                // create FreeImageBitmap from bitmap 
                // dauert ~ 5ms
                FreeImageBitmap obj = new FreeImageBitmap(_bmp[0]);
               // _bmpScorpion[0] = obj.GetHbitmap();
                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?

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 52



BeitragVerfasst: 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

ausblenden volle Höhe 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:
/// <summary>
    /// Performs application-defined tasks associated with freeing,
    /// releasing, or resetting unmanaged resources.
    /// </summary>
    /// <param name="disposing">If true managed ressources are released.</param>
    protected virtual void Dispose(bool disposing)
    {
      // Only clean up once
      lock (lockObject)
      {
        if (disposed)
        {
          return;
        }
        disposed = true;
      }

      // Clean up managed resources
      if (disposing)
      {
        if (stream != null)
        {
          if (disposeStream)
          {
            stream.Dispose();
          }
          stream = null;
        }
      }

      tag = null;
      saveInformation = null;

      // Clean up unmanaged resources
      UnloadDib();  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    }

                /// <summary>
    /// Tries to replace the wrapped <see cref="FIBITMAP"/> with a new one.
    /// In case the new dib is null or the same as the already
    /// wrapped one, nothing will be changed and the result will
    /// be false.
    /// Otherwise the wrapped <see cref="FIBITMAP"/> will be unloaded and replaced.
    /// </summary>
    /// <param name="newDib">The new dib.</param>
    /// <returns>Returns true on success, false on failure.</returns>
    private bool ReplaceDib(FIBITMAP newDib)
    {
      bool result = false;
      if ((dib != newDib) && (!newDib.IsNull))
      {
        UnloadDib();
        dib = newDib;
        AddMemoryPressure();
        result = true;
      }
      return result;
    }

/// <summary>
    /// Unloads currently wrapped <see cref="FIBITMAP"/> or unlocks the locked page
    /// in case it came from a multipaged bitmap.
    /// </summary>
    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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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 user profile iconTh69 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 52



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 52



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 03.03.17 19:14 
Das habe ich doch oben geschrieben. :gruebel:
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 03.03.17 21:08 
- Nachträglich durch die Entwickler-Ecke gelöscht -
doubleII Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 52



BeitragVerfasst: Do 09.03.17 10:10 
stimmt Th69 beim schreiben habe es übersehen. :D

Danke