huge memory leak in my game dll

Just starting out? Need help? Post your questions and find answers here.
rory-games
User
User
Posts: 31
Joined: Sun Feb 02, 2020 9:14 am
Contact:

huge memory leak in my game dll

Post by rory-games »

Hello,
I have made a game dll in PureBasic, to have menus, edit boxes, and a few other things. If it looks strange, it is just for audiogames. I would like to use this dll in python.
In PureBasic, all the functions work fine, with no problem, however in python, a huge memory leak occurs.
Here is my code. It is a bit long, but the problem seems to be with the second and 3rd modes (menu and edit box mode).
This code is very disorganized. I fully intend on cleaning it up later, this is more of an experiment than anything else at this stage.

Code: Select all

Global mode.i
Global Dim  keys2(512)
Structure event
value.i
type.i
EndStructure
Global NewList events.Event()
Global NewList trackedkeys()
Global NewMap keys()
Procedure error()
MessageRequester("error","An error occured. DLL line "+ErrorLine()+". "+ErrorMessage()+".",#PB_MessageRequester_Error)
EndProcedure
ProcedureCDLL Initialize(windowname.s)
OnErrorCall(@error())
mode=0
InitKeyboard()
InitSprite()
OpenWindow(1,1,1,1,1,windowname+" (powered by cgt)")
    keys("a")=#PB_Key_A
keys("b")=#PB_Key_B
keys("c")=#PB_Key_C
keys("d")=#PB_Key_D
keys("e")=#PB_Key_E
keys("f")=#PB_Key_F
keys("g")=#PB_Key_G
keys("h")=#PB_Key_H
keys("i")=#PB_Key_I
keys("j")=#PB_Key_J
keys("k")=#PB_Key_K
keys("l")=#PB_Key_L
keys("m")=#PB_Key_M
keys("o")=#PB_Key_O
keys("p")=#PB_Key_P
keys("q")=#PB_Key_Q
keys("r")=#PB_Key_R
keys("s")=#PB_Key_S
keys("t")=#PB_Key_T
keys("u")=#PB_Key_U
keys("v")=#PB_Key_V
keys("w")=#PB_Key_W
keys("x")=#PB_Key_X
keys("y")=#PB_Key_Y
keys("z")=#PB_Key_Z
keys("left")=#PB_Key_Left
keys("right")=#PB_Key_Right
keys("down")=#PB_Key_Down
keys("up")=#PB_Key_Up
keys("space")=#PB_Key_Space
keys("lcontrol")=#PB_Key_LeftControl
keys("rcontrol")=#PB_Key_RightControl
keys("lalt")=#PB_Key_LeftAlt
keys("ralt")=#PB_Key_RightAlt
keys("lshift")=#PB_Key_LeftShift
keys("rshift")=#PB_Key_RightShift
keys("1")=#PB_Key_1
keys("2")=#PB_Key_2
keys("3")=#PB_Key_3
keys("4")=#PB_Key_4
keys("5")=#PB_Key_5
keys("6")=#PB_Key_6
keys("7")=#PB_Key_7
keys("8")=#PB_Key_8
keys("9")=#PB_Key_9
keys("0")=#PB_Key_0
keys("escape")=#PB_Key_Escape
keys("comma")=#PB_Key_Comma
keys("semi")=#PB_Key_SemiColon
keys("tick")=#PB_Key_Apostrophe
keys("slash")=#PB_Key_Slash
keys("dot")=#PB_Key_Period
keys("lbracket")=#PB_Key_LeftBracket
keys("rbracket")=#PB_Key_RightBracket
keys("backslash")=#PB_Key_BackSlash
keys("backspace")=#PB_Key_Back
keys("enter")=#PB_Key_Return
keys("pageup")=#PB_Key_PageUp
keys("pagedown")=#PB_Key_PageDown
keys("home")=#PB_Key_Home
keys("end")=#PB_Key_End
keys("insert")=#PB_Key_Insert
keys("delete")=#PB_Key_Delete
keys("dash")=#PB_Key_Minus
keys("equals")=#PB_Key_Equals
TextGadget(1,1,1,1,1,"menu")
ListViewGadget(2,1,1,1,1)
TextGadget(3,1,1,1,1,"text input")
StringGadget(4,1,1,1,1,"")
HideGadget(1,1)
HideGadget(2,1)
HideGadget(3,1)
HideGadget(4,1)
EndProcedure
ProcedureCDLL TrackKey(key.s)
AddElement(trackedkeys())
trackedkeys()=keys(key)
EndProcedure
ProcedureCDLL ClearTrackedKeys()
ClearList(trackedkeys())
EndProcedure
ProcedureCDLL GetCurrentFrameEvents()
ClearList(events())
Repeat
event=WindowEvent()
If mode=2
If event=#PB_Event_Menu
AddElement(events())
events()\type=3
events()\value=GetGadgetState(2)+1
EndIf
If event=#PB_Event_Gadget
AddElement(events())
events()\type=2
events()\value=GetGadgetState(2)+1
EndIf
EndIf
If mode=3
If event=#PB_Event_Gadget
AddElement(events())
events()\type=4
events()\value=0
EndIf
If event=#PB_Event_Menu
events()\type=5
events()\value=0
EndIf
EndIf
Until event=#PB_Event_None
If mode=1
FlipBuffers()
ExamineKeyboard()
ForEach trackedkeys()
If KeyboardReleased(trackedkeys())
keys2(trackedkeys())=0
AddElement(events())
events()\type=1
events()\value=trackedkeys()
EndIf
If KeyboardPushed(trackedkeys()) And keys2(trackedkeys())=0
keys2(trackedkeys())=1
AddElement(events())
events()\type=0
events()\value=trackedkeys()
EndIf
Next
EndIf
LastElement(events())
AddElement(events())
events()\type=-1
ResetList(events())
EndProcedure
ProcedureCDLL NextFrameEvent()
NextElement(events())
EndProcedure
ProcedureCDLL EventInfo()
ProcedureReturn events()\type
EndProcedure
ProcedureCDLL EventValue()
ProcedureReturn events()\value
EndProcedure
ProcedureCDLL.s KeyValueToString(keyvalue.s)
kv=Val(keyvalue)
ForEach keys()
If keys(MapKey(keys()))=kv
ProcedureReturn MapKey(keys())
EndIf
Next
EndProcedure
ProcedureCDLL shutdown()
CloseWindow(1)
ClearMap(keys())
ClearList(trackedkeys())
For i = 0 To 512
keys2(i)=0
Next
mode=0
CloseScreen()
HideGadget(1,1)
HideGadget(2,1)
HideGadget(3,1)
HideGadget(4,1)
EndProcedure
ProcedureCDLL KeyPressed(key.s)
PushListPosition(events())
did=0
ForEach events()
If events()\type=0 And events()\value=keys(key)
did=1
EndIf
Next
PopListPosition(events())
ProcedureReturn did
EndProcedure
ProcedureCDLL KeyReleased(key.s)
PushListPosition(events())
did=0
ForEach events()
If events()\type=1 And events()\value=keys(key)
did=1
EndIf
Next
PopListPosition(events())
ProcedureReturn did
EndProcedure
ProcedureCDLL KeyDown(key.s)
ProcedureReturn keys2(keys(key))
EndProcedure

ProcedureCDLL KeyUp(key.s)
v=keys2(keys(key))
If v=1
ProcedureReturn 0
Else
ProcedureReturn 1
EndIf
EndProcedure
ProcedureCDLL SetTitle(title.s)
SetWindowTitle(1,title)
EndProcedure
ProcedureCDLL SetMode(modeset)
If modeset>0 And modeset<4
RemoveKeyboardShortcut(1,1)
Select mode
Case 1
CloseScreen()
Case 2
HideGadget(1,1)
HideGadget(2,1)
Case 3
HideGadget(3,1)
HideGadget(4,1)
EndSelect
mode=modeset
Select mode
Case 1
OpenWindowedScreen(WindowID(1),1,1,1,1)
Case 2 
HideGadget(1,0)
HideGadget(2,0)
SetActiveGadget(2)
AddKeyboardShortcut(1,#PB_Shortcut_Return,1)
Case 3
HideGadget(3,0)
HideGadget(4,0)
SetActiveGadget(4)
AddKeyboardShortcut(1,#PB_Shortcut_Return,1)
EndSelect
EndIf
EndProcedure
ProcedureCDLL SetInputText(text.s)
SetGadgetText(4,text)
EndProcedure
ProcedureCDLL.s GetInputText()
ProcedureReturn GetGadgetText(4)
EndProcedure
ProcedureCDLL ClearMenu()
ClearGadgetItems(2)
EndProcedure
ProcedureCDLL MenuSize()
ProcedureReturn CountGadgetItems(2)
EndProcedure
ProcedureCDLL AddMenuItem(item.s)
AddGadgetItem(2,-1,item)
EndProcedure
ProcedureCDLL EditMenuItem(index,newtext.s)
SetGadgetItemText(2,index-1,newtext)
EndProcedure
ProcedureCDLL RemoveMenuItem(index)
RemoveGadgetItem(2,index-1)
EndProcedure
ProcedureCDLL.s GetMenuItem(index)
ProcedureReturn GetGadgetItemText(2,index-1)
EndProcedure
Thanks much all for your help.
If anything in PureBasic could be causing this, some help finding it will be much appreciated; I am at a loss.
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: huge memory leak in my game dll

Post by mk-soft »

When creating DLLs, declarations must always be encapsulated in a procedure. See PB help.

There is no sufficient stack outside of procedures.
I have had the same experience. It crashed with Windows 7. When using modules, however, you can also create an init procedure within the module.
Procedure InitModule() : ;Do Any : Endprocedure : InitModule()

Code: Select all


CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  
  ; These 4 procedures are Windows specific
  ;
  
  ; This procedure is called once, when the program loads the library
  ; for the first time. All init stuffs can be done here (but not DirectX init)
  ;
  ProcedureDLL AttachProcess(Instance)
    Global mode.i
    Global Dim  keys2(512)
    Structure event
      value.i
      type.i
    EndStructure
    Global NewList events.Event()
    Global NewList trackedkeys()
    Global NewMap keys()
  EndProcedure
  
  
  ; Called when the program release (free) the DLL
  ;
  ProcedureDLL DetachProcess(Instance)
  EndProcedure
  
  
  ; Both are called when a thread in a program call or release (free) the DLL
  ;
  ProcedureDLL AttachThread(Instance)
  EndProcedure
  
  ProcedureDLL DetachThread(Instance)
  EndProcedure
  
CompilerElse
  
  Procedure InitDLL()
    Global mode.i
    Global Dim  keys2(512)
    Structure event
      value.i
      type.i
    EndStructure
    Global NewList events.Event()
    Global NewList trackedkeys()
    Global NewMap keys()
  EndProcedure

  InitDLL()
  
CompilerEndIf

Procedure error()
  MessageRequester("error","An error occured. DLL line "+ErrorLine()+". "+ErrorMessage()+".",#PB_MessageRequester_Error)
EndProcedure
ProcedureCDLL Initialize(windowname.s)
  OnErrorCall(@error())
  mode=0
  InitKeyboard()
  InitSprite()
  OpenWindow(1,1,1,1,1,windowname+" (powered by cgt)")
  keys("a")=#PB_Key_A
  keys("b")=#PB_Key_B
  keys("c")=#PB_Key_C
  keys("d")=#PB_Key_D
  keys("e")=#PB_Key_E
  keys("f")=#PB_Key_F
  keys("g")=#PB_Key_G
  keys("h")=#PB_Key_H
  keys("i")=#PB_Key_I
  keys("j")=#PB_Key_J
  keys("k")=#PB_Key_K
  keys("l")=#PB_Key_L
  keys("m")=#PB_Key_M
  keys("o")=#PB_Key_O
  keys("p")=#PB_Key_P
  keys("q")=#PB_Key_Q
  keys("r")=#PB_Key_R
  keys("s")=#PB_Key_S
  keys("t")=#PB_Key_T
  keys("u")=#PB_Key_U
  keys("v")=#PB_Key_V
  keys("w")=#PB_Key_W
  keys("x")=#PB_Key_X
  keys("y")=#PB_Key_Y
  keys("z")=#PB_Key_Z
  keys("left")=#PB_Key_Left
  keys("right")=#PB_Key_Right
  keys("down")=#PB_Key_Down
  keys("up")=#PB_Key_Up
  keys("space")=#PB_Key_Space
  keys("lcontrol")=#PB_Key_LeftControl
  keys("rcontrol")=#PB_Key_RightControl
  keys("lalt")=#PB_Key_LeftAlt
  keys("ralt")=#PB_Key_RightAlt
  keys("lshift")=#PB_Key_LeftShift
  keys("rshift")=#PB_Key_RightShift
  keys("1")=#PB_Key_1
  keys("2")=#PB_Key_2
  keys("3")=#PB_Key_3
  keys("4")=#PB_Key_4
  keys("5")=#PB_Key_5
  keys("6")=#PB_Key_6
  keys("7")=#PB_Key_7
  keys("8")=#PB_Key_8
  keys("9")=#PB_Key_9
  keys("0")=#PB_Key_0
  keys("escape")=#PB_Key_Escape
  keys("comma")=#PB_Key_Comma
  keys("semi")=#PB_Key_SemiColon
  keys("tick")=#PB_Key_Apostrophe
  keys("slash")=#PB_Key_Slash
  keys("dot")=#PB_Key_Period
  keys("lbracket")=#PB_Key_LeftBracket
  keys("rbracket")=#PB_Key_RightBracket
  keys("backslash")=#PB_Key_BackSlash
  keys("backspace")=#PB_Key_Back
  keys("enter")=#PB_Key_Return
  keys("pageup")=#PB_Key_PageUp
  keys("pagedown")=#PB_Key_PageDown
  keys("home")=#PB_Key_Home
  keys("end")=#PB_Key_End
  keys("insert")=#PB_Key_Insert
  keys("delete")=#PB_Key_Delete
  keys("dash")=#PB_Key_Minus
  keys("equals")=#PB_Key_Equals
  TextGadget(1,1,1,1,1,"menu")
  ListViewGadget(2,1,1,1,1)
  TextGadget(3,1,1,1,1,"text input")
  StringGadget(4,1,1,1,1,"")
  HideGadget(1,1)
  HideGadget(2,1)
  HideGadget(3,1)
  HideGadget(4,1)
EndProcedure
ProcedureCDLL TrackKey(key.s)
  AddElement(trackedkeys())
  trackedkeys()=keys(key)
EndProcedure
ProcedureCDLL ClearTrackedKeys()
  ClearList(trackedkeys())
EndProcedure
ProcedureCDLL GetCurrentFrameEvents()
  ClearList(events())
  Repeat
    event=WindowEvent()
    If mode=2
      If event=#PB_Event_Menu
        AddElement(events())
        events()\type=3
        events()\value=GetGadgetState(2)+1
      EndIf
      If event=#PB_Event_Gadget
        AddElement(events())
        events()\type=2
        events()\value=GetGadgetState(2)+1
      EndIf
    EndIf
    If mode=3
      If event=#PB_Event_Gadget
        AddElement(events())
        events()\type=4
        events()\value=0
      EndIf
      If event=#PB_Event_Menu
        events()\type=5
        events()\value=0
      EndIf
    EndIf
  Until event=#PB_Event_None
  If mode=1
    FlipBuffers()
    ExamineKeyboard()
    ForEach trackedkeys()
      If KeyboardReleased(trackedkeys())
        keys2(trackedkeys())=0
        AddElement(events())
        events()\type=1
        events()\value=trackedkeys()
      EndIf
      If KeyboardPushed(trackedkeys()) And keys2(trackedkeys())=0
        keys2(trackedkeys())=1
        AddElement(events())
        events()\type=0
        events()\value=trackedkeys()
      EndIf
    Next
  EndIf
  LastElement(events())
  AddElement(events())
  events()\type=-1
  ResetList(events())
EndProcedure
ProcedureCDLL NextFrameEvent()
  NextElement(events())
EndProcedure
ProcedureCDLL EventInfo()
  ProcedureReturn events()\type
EndProcedure
ProcedureCDLL EventValue()
  ProcedureReturn events()\value
EndProcedure
ProcedureCDLL.s KeyValueToString(keyvalue.s)
  kv=Val(keyvalue)
  ForEach keys()
    If keys(MapKey(keys()))=kv
      ProcedureReturn MapKey(keys())
    EndIf
  Next
EndProcedure
ProcedureCDLL shutdown()
  CloseWindow(1)
  ClearMap(keys())
  ClearList(trackedkeys())
  For i = 0 To 512
    keys2(i)=0
  Next
  mode=0
  CloseScreen()
  HideGadget(1,1)
  HideGadget(2,1)
  HideGadget(3,1)
  HideGadget(4,1)
EndProcedure
ProcedureCDLL KeyPressed(key.s)
  PushListPosition(events())
  did=0
  ForEach events()
    If events()\type=0 And events()\value=keys(key)
      did=1
    EndIf
  Next
  PopListPosition(events())
  ProcedureReturn did
EndProcedure
ProcedureCDLL KeyReleased(key.s)
  PushListPosition(events())
  did=0
  ForEach events()
    If events()\type=1 And events()\value=keys(key)
      did=1
    EndIf
  Next
  PopListPosition(events())
  ProcedureReturn did
EndProcedure
ProcedureCDLL KeyDown(key.s)
  ProcedureReturn keys2(keys(key))
EndProcedure

ProcedureCDLL KeyUp(key.s)
  v=keys2(keys(key))
  If v=1
    ProcedureReturn 0
  Else
    ProcedureReturn 1
  EndIf
EndProcedure
ProcedureCDLL SetTitle(title.s)
  SetWindowTitle(1,title)
EndProcedure
ProcedureCDLL SetMode(modeset)
  If modeset>0 And modeset<4
    RemoveKeyboardShortcut(1,1)
    Select mode
      Case 1
        CloseScreen()
      Case 2
        HideGadget(1,1)
        HideGadget(2,1)
      Case 3
        HideGadget(3,1)
        HideGadget(4,1)
    EndSelect
    mode=modeset
    Select mode
      Case 1
        OpenWindowedScreen(WindowID(1),1,1,1,1)
      Case 2 
        HideGadget(1,0)
        HideGadget(2,0)
        SetActiveGadget(2)
        AddKeyboardShortcut(1,#PB_Shortcut_Return,1)
      Case 3
        HideGadget(3,0)
        HideGadget(4,0)
        SetActiveGadget(4)
        AddKeyboardShortcut(1,#PB_Shortcut_Return,1)
    EndSelect
  EndIf
EndProcedure
ProcedureCDLL SetInputText(text.s)
  SetGadgetText(4,text)
EndProcedure
ProcedureCDLL.s GetInputText()
  ProcedureReturn GetGadgetText(4)
EndProcedure
ProcedureCDLL ClearMenu()
  ClearGadgetItems(2)
EndProcedure
ProcedureCDLL MenuSize()
  ProcedureReturn CountGadgetItems(2)
EndProcedure
ProcedureCDLL AddMenuItem(item.s)
  AddGadgetItem(2,-1,item)
EndProcedure
ProcedureCDLL EditMenuItem(index,newtext.s)
  SetGadgetItemText(2,index-1,newtext)
EndProcedure
ProcedureCDLL RemoveMenuItem(index)
  RemoveGadgetItem(2,index-1)
EndProcedure
ProcedureCDLL.s GetMenuItem(index)
  ProcedureReturn GetGadgetItemText(2,index-1)
EndProcedure
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
rory-games
User
User
Posts: 31
Joined: Sun Feb 02, 2020 9:14 am
Contact:

Re: huge memory leak in my game dll

Post by rory-games »

Aha, I see now. Much thanks! :D
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: huge memory leak in my game dll

Post by skywalk »

I initialized all my arrays inside AttachProcess(), but the rest of my Globals and Structures were in the main code.

Code: Select all

; PB DLL NOTES:
;   All arrays, linked-lists or maps with Dim, NewList or NewMap must be done in Procedure AttachProcess()!
;   No program code outside Procedures, except declaration of variables or structures.
;   DirectX initialization routines cannot be written in Procedure AttachProcess().
;   Only Global strings can be returned from the DLL.
;   Not sure where DataSections are handled, but no crashes so far.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
rory-games
User
User
Posts: 31
Joined: Sun Feb 02, 2020 9:14 am
Contact:

Re: huge memory leak in my game dll

Post by rory-games »

hmm, the leak still seems to occur. The most insane things about this is it's not like it's a minimal leak. It's maybe from 20 to 100 mb per second, or sometimes more. I have never seen something like this in my 3 years with pb.
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: huge memory leak in my game dll

Post by Mijikai »

If you still have the problem try to reduce the code step by step it may help to located the culprit.
It may also be helpful to add EnableExplicit at the top of the code.
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: huge memory leak in my game dll

Post by skywalk »

Did you read my note on DLL's?
You have text parameters and ProcedureReturns :shock:
You have to use pointers and structures.

EDIT: Make a simple Python program that only passes text back and forth to your DLL. Do it in a loop to simulate the leak.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Quin
Enthusiast
Enthusiast
Posts: 279
Joined: Thu Mar 31, 2022 7:03 pm
Location: United States
Contact:

Re: huge memory leak in my game dll

Post by Quin »

Perhaps I'm not calling it in the same way you are, but I just compiled and tested this, there don't seem to be any leaks. Perhaps the error is on the Python side?
PB v5.40/6.10, Windows 10 64-bit.
16-core AMD Ryzen 9 5950X, 128 GB DDR5.
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: huge memory leak in my game dll

Post by skywalk »

Yes, the poster mentioned no leak if PBDLL <-> PB. :idea:
My guess is sharing strings PBDLL <-> Python.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: huge memory leak in my game dll

Post by mk-soft »

I don't know how Python handles type B-STR. Have a look.

Code: Select all

ProcedureCDLL MyString()
  Protected *bstr, text.s
  text = "Hello World!"
  *bstr = SysAllocString_(text)
  ProcedureReturn *bstr
EndProcedure

; test

*r1 = MyString()
Debug PeekS(*r1)
SysFreeString_(*r1)
By default, when BSTR is passed to the function as a parameter, the caller releases the BSTR after the function. The PB compiler also does this internally for parameter type 'var.p-bstr'.
The return value is handled differently depending on the function.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Post Reply