Memory Leaks..
Übersicht

![]() |
FOODyBetreff: Memory Leaks.. |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hiho.
Ich hab ein Problem das mich schon länger beschäftigt: Memory Leaks. Habe mich immer gewundert wie die entstehen. Der Destruktor müsste doch alles zu "Null"en.... Ich hab ein kleinen Code geschrieben, der ein Leak entstehen lässt. Falls der Fehler an mir liegt, bitte bescheid geben ![]() Mir geht das einfach nur übelst auf den Sack und ich möcht das Problem entlich abspülen. Code: [AUSKLAPPEN] SuperStrict
Framework BRL.StandardIO Type FType Field mem:Byte Ptr Field par:FType Field i:Int Method New() ii:+1 mem = MemAlloc(1200) i=ii EndMethod Method Delete() Print "delete():"+i EndMethod Function Remove(t:Ftype Var) t.par=Null t=Null EndFunction Global ii:Int=0 EndType Print GCMemAlloced() Local t1:Ftype=New FType Local t2:Ftype=New FType Local t3:Ftype=New FType Local t4:Ftype=New FType t1.par=t2 t2.par=t1 t3.par=t4 t3.par=t1 Print GCMemAlloced() GCCollect() Print GCMemAlloced() FType.Remove(t1) FType.Remove(t2) FType.Remove(t3) FType.Remove(t4) GCCollect() Print GCMemAlloced() Hier ist ein Type. Ein ganz normaler eigentlich. Wenn man jetzt das par-Field leer lässt, wird alles ordnungsgemäß Getrashed, ansonsten tut sich nix und ein Leak entsteht. Nur t3 wird gelöscht, da auf ihn kein par-Field zeigt. Was soll ich tun? Was mache ich falsch? Auf ein "par"-Field kann ich nicht verzichten und ich würde den Dreck entlich gelöst bekommen.... Es muss doch irgendwie gehen. Wenn es ein Fehler meinerseits ist, oder sogar ein Denkfehler dann weist mich bitte daraufhin ![]() Gruß, FOODy PS: Tut mir leid wenn der Post jetzt irgendwie komisch geschrieben ist oder so, aber ich bin halb am Pennen und total verärgert ![]() |
||
BlitzMax + MaxGUI, 64-bit Arch Linux: Intel Core² E8500 | 8 GB Ram | GeForce GTX 460 · 1024 MB |
![]() |
Jolinah |
![]() Antworten mit Zitat ![]() |
---|---|---|
Beim kurzen drüber blicken ist mir nur folgendes aufgefallen:
Code: [AUSKLAPPEN] mem = MemAlloc(1200)
Speicher der auf diese Weise manuell reserviert wird, muss auch wieder manuell freigegeben werden. Der Garbagecollector wird ihn nicht aufräumen. Weiterhin geben Garbagecollectors den Speicher meist nicht sofort wieder frei, sie warten bis eine bestimmte Menge an Speicher reserviert wurde und räumen erst danach auf, damit dieser Prozess nicht andauernd durchgeführt wird. Das heisst es kann gut sein, dass deine Type-Instanzen noch nicht entsorgt werden, auch wenn keine Referenz mehr darauf zeigt. Die werden dann evtl. erst entsorgt wenn durch neue Objekte noch mehr Speicher reserviert wird oder wenn eine bestimmte Zeitfrist abläuft. Du kannst das zur Laufzeit testen indem du laufend neue Objekte erstellst und wieder auf Null setzt. Der Speicherverbrauch steigt auf ein gewisses Niveau an und stabilisiert sich dann, statt wie vielleicht erwartet praktisch 0 zu sein. |
||
![]() |
FOODy |
![]() Antworten mit Zitat ![]() |
---|---|---|
Ja so dachte ich es auch erst.
Aber wenn man jetzt die Zeilen, wo die par-Fields gesetzt werden auskommentiert werden _alle_ Instanzen entfernt. Das man Allokierten Speicher manuell freigeben muss ist klar. Aber das bringt wenig, wenn die Instanz nicht entfernt wird. (Da ich z.b. den Speicher im Destruktur freigeben würde) Gruß, FOODy EDIT: Hier z.b., werden alle Instanzen entfernt, da das par-Field nicht gesetzt ist. Wenn man die Zeilen aber mit Builded wird nur t3 entfernt, da auf die kein par-Field zeigt. Code: [AUSKLAPPEN] SuperStrict
Framework BRL.StandardIO Type FType Field mem:Byte Ptr Field par:FType Field i:Int Method New() ii:+1 mem = MemAlloc(1200) i=ii Print "new():"+i EndMethod Method Delete() Print "delete():"+i MemFree mem EndMethod Function Remove(t:Ftype Var) t.par=Null t=Null EndFunction Global ii:Int=0 EndType Print GCMemAlloced() Local t1:FType=New FType Local t2:FType=New FType Local t3:FType=New FType Local t4:FType=New FType Local t5:FType=t3 't1.par=t2 't2.par=t1 't3.par=t4 't3.par=t1 Print GCMemAlloced() GCCollect() Print GCMemAlloced() t5=Null FType.Remove(t1) FType.Remove(t2) FType.Remove(t3) FType.Remove(t4) GCCollect() Print GCMemAlloced() |
||
BlitzMax + MaxGUI, 64-bit Arch Linux: Intel Core² E8500 | 8 GB Ram | GeForce GTX 460 · 1024 MB |
![]() |
BtbN |
![]() Antworten mit Zitat ![]() |
---|---|---|
Öhm, der GC arbeitet via Reference Couting.
Und solang du nicht ALLE Referenzen auf deinen Type entfernst(Das muss nicht heißen auf NULL gesetzt haben), bleibt das auch. Und das handle auf eine Referenz an eine funktion zu übergeben, und dort die LOKALEN Referenz auf Null zu setzen ringt effektiv nix. Denn deine Gloablen referenzen bleiben erhalten, und werden logischerweise nicht gelöscht. Achja: Var dürfte bei types nicht funkitonieren. (Edit: Schwachsinn, offenbar gehts doch.) Edit 2: So, habe den fehler. Der grund dafür, dass es ohne die parents geht, und dass es mit parents ofenbar nicht geht ist: Du hast da ne kleine aber feine zyklische Struktur drinne: t1 hat als paerent t2, und t2 hat als parent t1. Das ist 1. Schwachsinn, dass sich 2 Objekte gegenseitig als Parent haben und 2. führt es dazu, dass es immer eine referenz auf t1 und t2 geben wird, und sie deshalb beide nicht gelöscht werden.(par in t1 zeigt auf t2 -> t2 wird nicht gelöscht ;; par in t2 zeigt auf t1 -> t1 wird nicht gelöscht) Hoffe, das war verständlich. |
||
![]() |
FOODy |
![]() Antworten mit Zitat ![]() |
---|---|---|
@BORNtobeNAMELESS:
Das war beabsichtigt, mit den gegenseitigen Parents. In diesem Beispiel ist das natürlich schwachsinn. Aber wenn man z.b. eine Map, List oder Array hat von den "Kinder"-Types und die Kind-Types ein Field haben, dass auf den Parent zeigt, ist es nicht unbedingt schwachsinnig, das gegenseitige Referenzieren. Oder ein anderes Beispiel. In BRL.LinkedList zeigen sich die TLink-Typen ja auch gegenseitig an. Zitat: Type TLink
Field _value:Object Field _succ:TLink,_pred:TLink [...] EndType @Var: Bei Var wird nicht die Referenz der Instanz vergeben, sondern die der Variable. Gruß, FOODy |
||
BlitzMax + MaxGUI, 64-bit Arch Linux: Intel Core² E8500 | 8 GB Ram | GeForce GTX 460 · 1024 MB |
![]() |
BtbN |
![]() Antworten mit Zitat ![]() |
---|---|---|
Meld dich mal bei ICQ irgendwie, hab da noch was zu gefunden, was den so besser gehen würde. | ||
![]() |
Markus2 |
![]() Antworten mit Zitat ![]() |
---|---|---|
Statt =New FType
kannst du eine Funktion nehmen die diese Struktur in eine Liste speichert . Und wenn du was entfernen willst gehst du die Liste durch und setzt da alle passenden Einträge auf NULL . Local Bla:FType=FType.Neu() function Neu:FType() local x:FType=new FType liste.addlast x return x end function die Idee mit Remove ist gut aber nicht korrekt Function Remove(t:Ftype Var) if t.par<>null then Ftype.Remove t.par t=Null End Function |
||
![]() |
FOODy |
![]() Antworten mit Zitat ![]() |
---|---|---|
@BORNtobeNAMELESS:
Falls du mich meinst, kann ich nur sagen das ich im moment auf der Arbeit bin ^^ @Markus2: Man kann die Instanz in ein Array speichern. Man kann die Instanz in einer Map speichern. UND, was hier anscheiend als unwichtig geltend gemacht wird, man kann die Instanz auch in einer normalen Variable speichern. Es dürfte dem GC eigentlich Esel sein, welche Speichermethode ich jetzt wähle. Die Instanz wird sowieso entweder in einem Field oder in einer Variable gespeichert. @Remove: Das würde ich so nicht sagen. Es müssten normalerweise nach dem entfernen einer Instanz auch automatisch alle Felder "entfernt/Nulliert" werden. Da würd ich sogar behaupt, dass ein t.par=null u.ä.s. überflüssig sind. Mal davon abgesehen das bei einer gegenseitigen Referenzierung wie in meinem Beispiel, die Funktion endlos-oft aufgerufen wird ![]() Gruß, FOODy PS: Falls ich etwas falsch verstanden habe, bitte ich um eine Aufklärung. |
||
BlitzMax + MaxGUI, 64-bit Arch Linux: Intel Core² E8500 | 8 GB Ram | GeForce GTX 460 · 1024 MB |
![]() |
Suco-XBetreff: .... |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hi
Das ist kein Leak, dass ist einfach der GC. Die genaue Logik von ihm kenne ich nicht, er sieht es aber scheinbar noch nicht für nötig, deine Daten zu entfernen, auch wenn du sie nicht mehr brauchst. Habe mal einen zweiten Test gemacht: Code: [AUSKLAPPEN] SuperStrict Framework BRL.StandardIO Type FType Field mem:Byte Ptr Field par:FType Field i:Int Method New() ii:+1 mem = MemAlloc(1200) i=ii EndMethod Method Delete() Print "delete():"+i EndMethod Function Remove(t:Ftype Var) t.par=Null t=Null EndFunction Global ii:Int=0 EndType DerTest() Print "DANACH" GCCollect() Print GCMemAlloced() Function DerTest() Print "DER TEST" Print GCMemAlloced() Local t1:Ftype=New FType Local t2:Ftype=New FType Local t3:Ftype=New FType Local t4:Ftype=New FType t1.par=t2 t2.par=t1 t3.par=t4 t3.par=t1 Print GCMemAlloced() GCCollect() Print GCMemAlloced() FType.Remove(t1) FType.Remove(t2) FType.Remove(t3) FType.Remove(t4) GCCollect() Print GCMemAlloced() End Function Wie du siehst, räumt er in der Funktion noch nicht auf. Aber danach räumt er alles aus dem Speicher, da es dann erst nötig wird. Du kannst dir also sicher sein, dass der GC die Daten garantiert so verwaltet, dass der Speicher immer Clean bleibt. Wenn du nicht zufällig alles mit Pointern und Speicherbereichen zukleisterst, brauchst du dir also über Leaks keine Sorgen zu machen. Mfg |
||
Intel Core 2 Quad Q8300, 4× 2500 MHz, 4096 MB DDR2-Ram, GeForce 9600GT 512 MB |
![]() |
FOODy |
![]() Antworten mit Zitat ![]() |
---|---|---|
@Suco-X:
Hmmm... Finde es aber dennoch etwas seltsam warum er mit einem par anders reagiert als ohne :S Werd mich dann wieder melden, wenn ich in diesem Bereich wieder ein Problem bekomme. :/ Danke, für eure Hilfe! ![]() Gruß, FOODy |
||
BlitzMax + MaxGUI, 64-bit Arch Linux: Intel Core² E8500 | 8 GB Ram | GeForce GTX 460 · 1024 MB |
Dreamora |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Er reagiert nicht anders, sondern genau gleich.
Aber wie oben geschrieben: Solange RefCount > 0 wird nicht aufgeräumt. BM hat kein Root Reference Count um zu sehen ob du überhaupt noch auf die Variable zugreifen kannst. Du musst via Remove Methoden selbst dafür sorgen das alle Referenzen aufgelöst werden bevor du das objekt "nullst" Ach ja, dein hauptmem leak ist trotzdem noch drin. Solange da in Method Delete() kein memfree self.mem steht gibts nen Leak. Nur wirst du den verpassen, denn GCMemAlloced gibt nur den von BM managten Speicher aus!! Das schliesst memalloc als auch soundfiles explizit aus (da sie über C Memory Funktionen laufen), deren speicherverbrauch bekommst du dann im prozessmanager entgegengeschleudert ![]() |
||
Ihr findet die aktuellen Projekte unter Gayasoft und könnt mich unter @gayasoft auf Twitter erreichen. |
![]() |
FOODy |
![]() Antworten mit Zitat ![]() |
---|---|---|
@Dreamora:
Beim Zweiten Code hatte ich nen MemFree "eingebaut", aber das ist ja nicht das Problem, welches ich habe, da ich MemAlloc sowieso fast nie verwende. Mein Problem ist nur, das ich einen Styleparser habe für meine Gui, und wenn man jedesmal einen neuen Style läd, immer mehr Speicher reserviert wird, obwohl ich im Destruktor alles vernichte. (Ich verwende weder Pointer noch MemAlloc) Kann es eigentlich auch sein, das wenn man z.b. in einer Map Instanzen hat, und die Map zerstört, dass dann dennoch die Instanzen am "leben" bleiben? Weil bei mir die Instanzen erst freigegeben wurden als ich vor dem Leeren und vernichten der Map, die Instanzen durchgegangen bin und einzeln "Methodenmäßig" gelöscht habe. Könnte mich aber auch Irren :S Oder die wären sogar erst später gelöscht worden, als wenn ich das direkt mache. Gruß, FOODy |
||
BlitzMax + MaxGUI, 64-bit Arch Linux: Intel Core² E8500 | 8 GB Ram | GeForce GTX 460 · 1024 MB |
![]() |
Suco-XBetreff: ..... |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hi Foody
Normalerweise solltest du eine Map/Liste einfach zerstören können, ohne die darin enthaltenen Distanzen Manuell zu nullen. Vorrausgesetzt, diese Instanzen zeigen nicht noch irgendwo anders hin. Das ganze kann man ja wieder mit einem Test nachprüfen: Code: [AUSKLAPPEN] Strict Type TStyle Field X:Int, Y:Int Field i:Int Global Index:Int Method New() Index:+1 i = Index End Method Method Delete() Print I+": "+"Delete" End Method End Type Wush() GCCollect() Function Wush() Local Map:TMap = New TMap For Local i:Int= 0 Until 1000 Map.Insert(String(i), New TStyle) Next End Function Geht alles weg. Zu deinem anderen Problem. Schau dir mal dieses Beispiel hier an Code: [AUSKLAPPEN] Strict Type TStyle Field X:Int, Y:Int Field i:Int Global Index:Int Method New() Index:+1 i = Index End Method Method Delete() Print I+": "+"Delete" End Method End Type Graphics 800,600,0 Repeat Cls Local Style:TStyle Style = New TStyle DrawText GCMemAlloced(),10,10 Flip Until KeyHit(KEY_ESCAPE) Wie du siehst, räumt er immer nur stückchenweise den Speicher auf, wenn er zu voll wird. Sicher, dass dies nicht der Fall ist, den du als Fehler ansiehst? Mfg |
||
Intel Core 2 Quad Q8300, 4× 2500 MHz, 4096 MB DDR2-Ram, GeForce 9600GT 512 MB |
![]() |
FOODy |
![]() Antworten mit Zitat ![]() |
---|---|---|
@Suco-X:
Hmmm... Das ist gut, dass es geht. Dann werde ich wohl einen Fehler im Code übersehen haben, denn der Allokierte Speicher steigt jedesmal wenn ich einen Style "überlade" (alten Löschen, neuen Laden) (Als "ob" der Alte noch da wäre (also nicht gelöscht wurde)). Werde mal, wenn ich Zeit habe einen kleinen DebugCounter machen bei den Types, um zu schauen wo was nicht gelöscht wird. ( Toll, das mir diese Idee erst jetzt an den Kopf geprallt ist >_> ) Danke, Suco-X. ![]() Gruß, FOODy |
||
BlitzMax + MaxGUI, 64-bit Arch Linux: Intel Core² E8500 | 8 GB Ram | GeForce GTX 460 · 1024 MB |
![]() |
FOODy |
![]() Antworten mit Zitat ![]() |
---|---|---|
Irgendwie check ich mal wieder was nicht.
Wieso werden hier nicht alle Instanzen zerstört? Code: [AUSKLAPPEN] SuperStrict
Import BRL.GLMax2D Type TType Field p:TType Field n:Int Method New() total:+1 n=total list.addlast Self EndMethod Method Delete() Print n Destroy() total:-1 EndMethod Method Destroy() p=Null EndMethod Function Clear() For Local t:TType=EachIn list t.Destroy() Next list.clear() EndFunction Global list:TList=New TList Global total:Int EndType Graphics 480,320 (New TType).p = New TType New TType New TType New TType Local t1:TType = New TType Local t2:TType = New TType t1.n = 500 t2.n = 600 t1.p = t2 Repeat Cls If MouseHit(MOUSE_RIGHT) t1=Null t2=Null TType.Clear() '.list EndIf DrawText TType.total,5,5 Flip GCCollect() Until KeyDown(KEY_ESCAPE) Blick da nicht irgendwie rüber warum das nicht geht........ Wär mal nen schönes Feature wenn man auch manuell Objekte Zerstören könnte -.- Weiß da jemand woran das liegt? Ist bestimmt wieder ein denkfehler meinerseits... Gruß, FOODy PS: Und warum wird bei diesem Beispiel nur ein Objekt zerstört?! (Bei welchem kein SetN eingesetzt wurde) Code: [AUSKLAPPEN] SuperStrict
Import BRL.GLMax2D Type TType Field p:TType Field n:Int Method New() total:+1 n=total list.addlast Self EndMethod Method Delete() Print n Destroy() total:-1 EndMethod Method SetN:TType(n:Int) self.n=n Return Self EndMethod Method Destroy() p=Null EndMethod Function Clear() For Local t:TType=EachIn list t.Destroy() Next list.clear() EndFunction Global list:TList=New TList Global total:Int EndType Graphics 480,320 (New TType).SetN(1).p = (New TType).SetN(2) (New TType).SetN(3) (New TType).SetN(4) (New TType).SetN(5) Local t1:TType = New TType Local t2:TType = New TType t1.n = 500 t2.n = 600 t1.p = t2 Repeat Cls If MouseHit(MOUSE_RIGHT) t1=Null t2=Null TType.Clear() '.list EndIf DrawText TType.total,5,5 Flip GCCollect() Until KeyDown(KEY_ESCAPE) Kann doch nicht dran liegen das SetN ne Referenz der instanz zurückgibt -_-" |
||
BlitzMax + MaxGUI, 64-bit Arch Linux: Intel Core² E8500 | 8 GB Ram | GeForce GTX 460 · 1024 MB |
![]() |
FOODy |
![]() Antworten mit Zitat ![]() |
---|---|---|
Ich bekomm das einfach nicht hin :/
Habe mal das "Problem" hochgeladen. Wenn man bei der main.bmx jetzt die definierungen von class und frame auskommentiert (nicht die deklarierung sondern nur die wertzuweisung) werden alle FStyleClass und FStyleFrame Instanzen Zerstört ansonsten bleibt eine Class und eine Frame Instanz übrig. (obwohl ich vor der Löschung beide Variablen noch auf Null gesetzt habe) Download: http://www.onkel-foody.de/Daten/FStyle.rar Ich hoffe ihr könnt mir helfen... Gruß, FOODy |
||
BlitzMax + MaxGUI, 64-bit Arch Linux: Intel Core² E8500 | 8 GB Ram | GeForce GTX 460 · 1024 MB |
Dreamora |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Hab mir das hochgeladene net angesehen nur den code oben.
Da verwendest du auf Main Scope ebene Local ... die werden immer bestehen bleiben, denn locals haben, wenn der Scope nicht endet, kein definiertes ende. Will heissen wenn du sie auf "Mainloop" Ebene nutzt werden sie erst mit der zerstörung des Programmes auch aufgehoben, vorher nicht, da ein = NULL sie während des laufenden Scopes nur bedingt interessiert. Auf Hauptprogrammebene alles global definieren oder garnicht definieren und direkt eine Managerklasse nehmen. |
||
Ihr findet die aktuellen Projekte unter Gayasoft und könnt mich unter @gayasoft auf Twitter erreichen. |
![]() |
FOODy |
![]() Antworten mit Zitat ![]() |
---|---|---|
@Dreamora:
Das ergibt irgendwie Sinn und scheint auch logisch zu sein. Danke, Dreamora! Bei weiteren Unklarheiten werd ich mich wieder melden ![]() Danke nochmal an alle hier, die sich Zeit genommen haben mir zu helfen ![]() Gruß, FOODy |
||
BlitzMax + MaxGUI, 64-bit Arch Linux: Intel Core² E8500 | 8 GB Ram | GeForce GTX 460 · 1024 MB |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group