MemLeak in Max2D?

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

Holzchopf

Meisterpacker

Betreff: MemLeak in Max2D?

BeitragFr, Aug 28, 2009 0:20
Antworten mit Zitat
Benutzer-Profile anzeigen
Guten Morgen liebe BlitzMax-Fangemeinde! Heute geht's mal früh zur Sache:

Folgendes: Ich hatte gestern erfolglos versucht, die Ramauslastung in einem BMax-Programm nach unten zu drücken... Irgendwann kam ich zum Entschluss:
Entweder, ich mache etwas gehörig falsch, oder Max2D resp DrawImage verursacht irgendwo ein Memory Leak.

Als Demonstration habe ich folgenden Code. Er erstellt ein 400x300px Bild mit 20 Frames, die im Sekundentakt gewechselt werden. Laut meiner Rechnung sollte das ~10MiB RAM füllen.
Aber - und das ist seltsam - jedes Frame, das zum ersten mal auf dem Bildschirm gezeichnet wird, lässt die Auslastung gute 2MiB nach oben schnellen =/
Insgesamt gehts bei mir auf 57MiB...

BlitzMax: [AUSKLAPPEN]
SuperStrict

Rem
*************************

Ram-Füller-Code

-------------------------

Was bei mir geschieht:
Dieser Code generiert eine Art Memory-Leak.
Und zwar erhöht sich mit jedem Frame, das neu
gezeichnet wird (zum ersten mal auf den Bild-
schirm kommt), die Speicherauslastung des
Programms (beobachtbar im Taskmanager).

Und das ziemlich deutlich:
Bei 20 Frames à 400x300 px betragen die RAM-
Sprünge >2MB.
Schlussendlich geht die Speicherauslastung bis
auf über 55MB rauf - ich finde, für ein so
simples Programm ist das nicht wirklich akzept-
abel.

Falls das bei euch auch so ist, wär__COMMENT1__
scheinlich nicht schlecht, dem mal auf den
Grund zu gehen...

Achja:
400x300 px = 120000 px
x 4 Byte/px = 480000 Byte
x 20 (Frames) = 9600000 Byte
= 9375 KiB
= 9.2 MiB

Also laut meiner Rechnung, würden 10MiB für dieses
Programm reichen...

*************************
End Rem


' Anzahl Frames, die erstellt werden, und wie lange es dauert,
' bis der Spuk ein Ende hat.
Const Frames:Int = 20

' Jeden Frame mit einer Farbe füllen
Local Image:TImage = CreateImage(400,300,Frames,DYNAMICIMAGE)
For Local frame:Int = 0 To Frames -1
Local Pixmap:TPixmap = LockImage( Image, frame )
ClearPixels( Pixmap, $FF880000 | frame *$FF99 )
UnlockImage( Image, frame )
Next

' Ganz normales Grafikfenster, oder liegt hier etwa der Fehler?
Graphics 400,300,0,60

' Zeitsteuerung
Local MSec:Int = MilliSecs(), Frame:Int = 0, FrameTime:Int = MSec +1000

' Hauptschleife
While Not (KeyDown(KEY_ESCAPE ) Or AppTerminate())
MSec = MilliSecs()

' Im Sekundentakt Frame wechseln
If MSec => FrameTime
FrameTime:+ 1000
Frame = (Frame +1) Mod Frames
EndIf

' Grafikausgabe
Cls

DrawImage Image, 0, 0, Frame

Flip
Wend
End


Passiert bei euch das gleiche? Selber Effekt? Selbe (Aus-)Wirkung? Habe BMax 1.33

Und wenn ja: Hat jemand eine Idee, was man dagegen tun könnte? =(

mfG

Edit
Es macht übrigens bei mir keinen Unterschied, ob ich nun
BlitzMax: [AUSKLAPPEN]
Framework BRL.GlMax2D

oder auch
BlitzMax: [AUSKLAPPEN]
Framework BRL.D3D7Max2D

verwende =/
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm
 

Ava

Gast

BeitragFr, Aug 28, 2009 6:17
Antworten mit Zitat
Vermutung liegt nahe, dass ein DynamicImage sowohl die Pixmap, als auch das Image speichert - und somit etwa doppelten Speicher verbraucht. Das würde auch erklären, warum der Speicherbedarf beim ersten Zeichnen steigt: Er läd die Pixmap als Image hoch (aktualisiert es quasi).

So ist das zumindest bei meiner GFX-Engine. Smile

(Habe jetzt aber noch nicht direkt in den Source geschaut, um diese Vermutung abzusichern ^^)

Nicdel

BeitragFr, Aug 28, 2009 8:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich habs jetzt auch mal getestet und bin zu folgendem Ergebnis gekommen:

GLMax2D: ca. 60 MiB

D3D7Max2D: ca. 36 MiB

D3D9Max2D: ca. 40 MiB
Desktop: Intel Pentium 4 2650 Mhz, 2 GB RAM, ATI Radeon HD 3850 512 MB, Windows XP
Notebook: Intel Core i7 720 QM 1.6 Ghz, 4 GB DDR3 RAM, nVidia 230M GT, Windows 7

Holzchopf

Meisterpacker

BeitragFr, Aug 28, 2009 11:25
Antworten mit Zitat
Benutzer-Profile anzeigen
@ Ava: Das könnte eine Erklärung sein. Zumindest so halb. Denn ein 400x300 Pixmap sollte keine 2MiB beanspruchen. Und doppelter Speicherverbrauch find' ich sowieso grad mal ziemlich ungünstig Confused Also, mir würde wohl keiner erklären können, wofür das unbedingt nötig sein sollte. Und wenn doch, würd ich's einfach nicht akzeptieren. Wenn die Bytes schon im RAM liegen, dann sollen die gefälligst auch gebraucht werden.

Aber um der DYNAMICIMAGE-Theorie nachzugehen, habe ich mal ein 400x300 Bild mit 20Frames erstellt, abgespeichert und mit verschiedenen Flags bei LoadAnimImage geladen und folgendes beobachtet:
Code: [AUSKLAPPEN]
OpenGL

DYNAMICIMAGE     69MiB
FILTEREDIMAGE    69MiB
MASKEDIMAGE      72MiB
MIPMAPPEDIMAGE   56MiB


D3D7

DYNAMICIMAGE     58MiB
FILTEREDIMAGE    58MiB
MASKEDIMAGE      61MiB
MIPMAPPEDIMAGE   84MiB


Also am DYNAMICIMAGE-Flag bei Bildern, die während der Laufzeit erstellt werden, scheints schon mal nicht zu liegen =/

Weiter habe ich folgendes Probiert: Das Bild nicht als AnimImage zu laden, sondern einfach mit LoadImage laden und mit Offset-Verschiebung und ViewPort das zeichnen eines Quasi-Frames zu erzwingen... Ergebnis:
Code: [AUSKLAPPEN]
OpenGL

DYNAMICIMAGE     31MiB
FILTEREDIMAGE    31MiB
MASKEDIMAGE      23MiB
MIPMAPPEDIMAGE   31MiB


D3D7

DYNAMICIMAGE     54MiB
FILTEREDIMAGE    54MiB
MASKEDIMAGE      56MiB
MIPMAPPEDIMAGE   79MiB


Während unter Direct3D7 keine enorme Verbesserung feststellbar ist, sieht man bei OpenGL - oder sehe ich und wage daraus zu schliessen -, dass offenbar durch das Extrahieren des Frames aus dem Pixmap eine Kopie des Bereichs erzeugt wird. Aber auch das entschuldigt noch keine 2MiB Sprünge. Denn angenommen, dass das 400x300 Pixmap in einer 512x512px, 32Bit/Pixel "Textur" untergebracht wird, gäbe das gerade mal 1MiB.

Also ich denke, hier kann man - ohne etwas zu überstürzen - eine Optimierung verlangen.

Der Workaround mit dem ViewPort scheint aber, dank D3D7 Confused, auch nicht gerade eine gute Alternative zu sein.

Zurück zu dir, Ava: Wie weit baut denn deine Gfx-Engine auf BMax auf? Also, welche Module hast du anangetastet gelassen? Liegt das evtl an der OpenGl- /DirectX-Implementierung in BMax oder ist das doch ein Problem, das tiefer begraben liegt? Wär mir zwar neu, dass alle D3D7- und OGL-Anwendungen das gleiche Verhalten aufweisen =/

@ Nicdel: Danke fürs testen! Ich hatte zuerst die Vermutung, dass das Problem von meiner Hardware verursacht wird, aber je mehr Leute mir zumindest ein ähnlich hohes Ergebnis bestätigen können, umso mehr verschwindet diese Vermutung.

Jetzt bleibt immer noch die Frage, ob das Problem nun ich mit dem Code verursacht habe (habe ich irgendwas missachtet?), oder ob das in der Tat ein unschönes BMax-Feature ist. Gibts hierzu experten-Meinungen? Rolling Eyes
Und ich wäre froh, wenn ich noch mehr Aussagen dazu bekäme Wink

mfG
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm
 

ChristianK

BeitragFr, Aug 28, 2009 15:48
Antworten mit Zitat
Benutzer-Profile anzeigen
Holzchopf hat Folgendes geschrieben:
Und doppelter Speicherverbrauch find' ich sowieso grad mal ziemlich ungünstig Confused Also, mir würde wohl keiner erklären können, wofür das unbedingt nötig sein sollte. Und wenn doch, würd ich's einfach nicht akzeptieren. Wenn die Bytes schon im RAM liegen, dann sollen die gefälligst auch gebraucht werden.

Ohne dieses "Feature" würde dein oben genanntes Beispiel nicht funktionieren. Für jedes Bild bzw. jeden Frame wird eine Pixmap im Systemspeicher abgelegt. Erst wenn das Bild zum ersten mal gezeichnet wird, erstellt der entsprechende Max2D-Driver eine Kopie im Videospeicher durch OpenGL oder Direct3D (nicht nur bei DYNAMICIMAGE). Das hat den Vorteil, dass Graphics auch aufgerufen werden kann, nachdem ein Bild erstellt oder geladen wurde. Man kann dadurch auch den Max2D-Driver während der Laufzeit wechseln, ohne alle Bilder neu zu laden. Ohne die Kopie im Systemspeicher gingen die Daten jedes mal verloren.
AdvanceLcd
Intel Core 2 Duo 3.2 GHz, 4 GB RAM, GeForce 8800 GTX | MacBook Pro 15,4″ Intel Core 2 Duo 2.4 GHz, 2 GB RAM, GeForce 8600M GT

Holzchopf

Meisterpacker

BeitragFr, Aug 28, 2009 15:52
Antworten mit Zitat
Benutzer-Profile anzeigen
Kann man dieses Feature denn irgendwie ausschalten? Oder die im Systemspeicher abgelegten Kopien irgendwie freigeben? Aber wie schon gesagt, 2MiB für n 400x300 Pixmap sind ziemlich viel...
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

BtbN

BeitragSo, Aug 30, 2009 18:53
Antworten mit Zitat
Benutzer-Profile anzeigen
Erstmal: Zuerst Graphics, dann das Image, nicht andersrum. Dann: Max2D hält 2 Pixmaps, quasi: Einmal die komplett-Pixmap, und dann einmal jede zerschnittene Einzel-Pixmap. Daher der genau doppelte verbrauch.
Zudem kommen noch diverse vorgeladene sachen von Modulen, vorallem da du kein Framework setzt.
Ein Framework auf das nötigste sollte den Ram-Verbrauch schonmal senken.
Die Images auf der GraKa(Texturen) zählen übrigens nicht zum Ram-Verbrauch. Zudem muss man beachten, dass BMax intern die pixmap auf die nächste quadratzahl hochskaliert(Also in dem fall hier 512x512 Pixel)
Zu Mipmapped-Image: Dass das mehr verbraucht, ist logisch: Es wird das anfangsbild genommen, gespeichert, auf die halbe auflösung runterskaliert, gespeichert, skaliert, ... bis es nurnoch 1x1 groß ist.
So können kleinere bilder schneller gezeichnet und rotationen sauberer dargestellt werden.

Holzchopf

Meisterpacker

BeitragSo, Aug 30, 2009 19:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke für die Antwort, aber bis auf "zuerst Graphics, dann Images", sagst du mir leider nichts neues.

Wie du ja im ersten Post gelesen hast, machts keinen unterschied, ob ich ein Framework setze oder nicht - und wenn, obs GlMax2D ist oder D3D7Max2D Wink Auch sollten die Module nicht einfachso mal den Ram-Verbrauch auf 57MiB hochschrauben...

Das mit dem zuerst Graphics und dann Images hab ich auch glatt probiert - brachte aber nix Sad

Und auch - wie auch schon bereits erwähnt - wenn die Images in 512x512px Texturen untergebracht werden, kann ich mir die 2MiB Sprünge nicht erklären...
... erst recht nicht, wenn du sagst, dass Texturen nicht zum Ram-Verbrauch zählen Confused Das geht mir jetzt überhaupt nicht mehr auf. Ich meine, dass das so wäre, dachte ich auch, aber dann kommt der Taskmanager und sagt mir, dass diese billige App so viel Ram beansprucht. Ist mir einfach schleierhaft... Confused

Das mit Mipmapped-Image war mir auch noch irgendwoher logisch (wahrscheinlich, weils schon in den Doks steht *hust*), aber wenn man irgendwas recherchieren will, sollte man auch nix auslassen - gut, ich gebs zu, ich habe nicht alle Flag-Kombinationen ausprobiert (höchstens noch alle Flags gleichzeitig setzen, aber noch höher hab ich die Ram-Auslastung nicht hingebracht...

Also, mal ein anderer Ansatz (da du ja eines auch Bestätigst - und mit deinen, Avas und ChristianKs Argumenten glaube ich das gerne): Wenn BMax zwei kopien hält - und eine davon im Graka-Speicher, der nicht zur Ram-Auslastung zählt - wie kann dann ein 512x512px Pixmap 2MiB zusätzlichen Speicher verursachen? Ich könnte mich jetzt ja durch den Modul-Urwald von BMax kämpfen und schauen, ob evtl DrawImage eine Kopie erstellt und die Methode zum zeichnen des Pixmaps noch eine weitere - aber ich weiss nichtmal, ob ich das herausfände Confused

Ist ja offenbar ein BMax-Only-Feature, also sollte es doch irgendwie möglich sein, das zu umgehen?

mfG
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

BtbN

BeitragSo, Aug 30, 2009 19:46
Antworten mit Zitat
Benutzer-Profile anzeigen
DrawImage kopiert garnichts, es aktiviert nur die Textur und zeichnet ein quadrat. Der zusätzliche ram-Verbrauch muss von anderen Modul-Interna kommen.
Hast du schonmal versucht, ein GC-Collect mit in die Hauptschleife einzubauen, und deine nicht mehr benutzten Pixmap-Variablen und Image-Variablen = Null zu setzen, nachdem du sie benutzt hast?

Holzchopf

Meisterpacker

BeitragSo, Aug 30, 2009 19:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Oh, tschuldigung, mein Fehler Embarassed ich hatte ursprünglich ein GCCollect() drin (hatte das Problem zuerst im Chat besprochen und den Code ins Archiv gestellt, dort wars afaik noch drin), aber es hat nix gebracht und ich habs für den Thread-Code rausgenommen Embarassed

Mit Pixmap = Null hat leider auch nix geändert =(
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

mahe

BeitragSo, Aug 30, 2009 20:32
Antworten mit Zitat
Benutzer-Profile anzeigen
Also wenn Du Deine Rechnung aus dem ersten Code anpasst kommst Du auf 40 MB Verbrauch. Der Rest zu den 57 MB kann man sich dann durchaus mit Modulen, Rundherum usw. erklären.

Code: [AUSKLAPPEN]
 400x300 px = 120000 px
x 4 Byte/px = 480000 Byte
x 20 (Frames) = 9600000 Byte
= 9375 KiB
= 9.2 MiB


angepasst:

Code: [AUSKLAPPEN]
 512x512 px = 262144 px    ;So groß muss das Bild wirklich sein
x 4 Byte/px = 1048576 Byte
x 20 (Frames) = 20971520 Byte
= 20480 KiB
= 20 MB * 2 = 40 MB    ;Nochmal mal 2 weil es laut BtbN 2x vorgehalten wird


Auch die 2-MB-Sprünge sollten jetzt erklärbar sein.
ʇɹǝıdɯnɹɹoʞ ɹnʇɐuƃıs - ǝpoɥʇǝɯ-ɹoɹɹıɯ ɹǝp uı ,ɹoɹɹǝ,

Holzchopf

Meisterpacker

BeitragSo, Aug 30, 2009 20:38
Antworten mit Zitat
Benutzer-Profile anzeigen
Zählen denn nun die Kopien, die ja auf der GraKa gespeichert werden, zum Ram-Verbrauch oder nicht? Oder werden die gar nicht auf der GraKa gespeichert? Dann gings auf... Also, mal davon abgesehen, dass ich ganz pingelig bin und die zusätzlichen 17MiB immer noch nicht akzeptiere Razz
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

mahe

BeitragSo, Aug 30, 2009 22:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Die Kopie auf der GraKa ist da nicht eingerechnet. Dort müsste es spätestens beim Zeichnen nochmals hinkopiert werden. Ich vermute aber mal ganz stark, dass es immer auch im RAM liegen muss weil der Platz auf der GraKa ja durchaus sehr begrenzt sein kann und dann da öfter was überschrieben werden muss.

Die zusätzlichen 17 MB könntest Du möglicherweise reduzieren wenn Du 'Framework' und 'Import' verwendest und so nur die wirklich benötigten Module lädst.
ʇɹǝıdɯnɹɹoʞ ɹnʇɐuƃıs - ǝpoɥʇǝɯ-ɹoɹɹıɯ ɹǝp uı ,ɹoɹɹǝ,

Holzchopf

Meisterpacker

BeitragSo, Aug 30, 2009 22:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Wie schon gesagt, auch wenn ich Framework BRL.GlMax2D einbinde (sonst keine Module, läuft ja so), siehts mit der Ram-Auslastung genau gleich aus.

Heisst dass aber, Max2D macht 2 Kopien? Eine nochmal im Ram und eine auf dem GraKa-Speicher?
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

BtbN

BeitragMo, Aug 31, 2009 17:32
Antworten mit Zitat
Benutzer-Profile anzeigen
Ein Image liegt IMMER als Textur im Ram der GraKa, sobald man es läd. Zusätzlich hält BMax in einem Image aber auch eine Pixmap des bildes im Ram, um es bei veränderungen neu hochladen zu können.
Dabei existiert eine Pixmap pro Frame, und u.U. nochmal eine Gesammt-Pixmap mit allen Frames aneinander.
Und nein, es liegt wirklich IMMER im VRam, wenn dort voll ist, ist sense mit dem Programm. Allerhöchstens hält der Treiber das bild nochmal im Ram, was ich aber wiederrum für sehr unwahrscheinlich halte. Und was im VRam liegt, zählt NICHT zum normalen Ram-Verbrauch.

Holzchopf

Meisterpacker

BeitragMo, Aug 31, 2009 17:43
Antworten mit Zitat
Benutzer-Profile anzeigen
Ok, sehr ausführlich, danke =)

Das heisst, wenn man Frames auch immer schön in ein 2er-Potenz-Quadrat-Raster (verständlich? sollte schon...) bringt und voll ausnützt, kann man u.U. schon was sparen? Dank Echtzeit-Transformationen kann man ja in Extremfällen ein Bild auch etwas kleiner speichern und hoch skalieren...

Und dann gibt's ja noch die zerschnippsel-Lösung*, die zumindest bei mir unter OGL schon ziemlich was bringt Wink
edit: *Per Viewport, wohlgemerkt Wink

Ich kann's momentan leider nicht testen, aber erzeugen 3D-Module (minib3d und co) auch Texturkopien? Weiss das grad jemand? *liebindierundeguck* Mr. Green
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group