Page 1 of 1

Finding leaking memory - what function to use?

Posted: Wed Mar 28, 2012 2:05 pm
by jesperbrannmark
Hi.
I am trying to find a memleak issue.
I am limited to using activity monitor and look for any increase and then guess what function (from debugger output) is running at that time.
Yesterday my program was running using 1.2 GB RAM and now I got it down to around 80 MB - but it still increases everytime I do something.

Is there a function to return the amount of memory used by the program as a integer? That is really what I would need, because then I can put something in the beginning and end of the procedures I want to pinpoint, like:

Code: Select all

Procedure MyFunction()
  StartMem.i = FUNCTIONTOGETMEMORY()
  ;code goes here
  Debug Str(FUNCTIONTOGETMEMORY()-StartMem)+" bytes used by function"
Endprocedure
Similar to what I can do with ellapsedmilliseconds() - but for memory?

Re: Finding leaking memory - what function to use?

Posted: Wed Mar 28, 2012 2:50 pm
by skywalk
Search for noleak from luis.

Re: Finding leaking memory - what function to use?

Posted: Wed Mar 28, 2012 3:07 pm
by jesperbrannmark
That could be handy, but honestly - I dont use any of the functions its tracing so it will not help me this time.
I really need to know size allocated memory (total) at beginning and end of a procedure.

Re: Finding leaking memory - what function to use?

Posted: Wed Mar 28, 2012 4:06 pm
by jesperbrannmark
Yes. Looking at noleak, variable viewer and comparing PC to MAC I can definitely say that the memory leak is only on MAC. This bring me to think that some function in PB is not freeing up memory like it does on the PC.
There must be someone cleaver that know how to get program used memory...

Re: Finding leaking memory - what function to use?

Posted: Thu Mar 29, 2012 10:40 am
by jesperbrannmark
OK. I tried AppleScript and it works somewhat.
I need first a way to replace this
a.s="set pid to pidOfRunningApp("+Chr(34)+"PureBasic1"+Chr(34)+")"+#CRLF$
with actual executable name instead of "PureBasic1". Is there a string with the compiled programs filename?

Test program:

Code: Select all

;memleaktest.pb
;checks for allocated memory of program
;saves output in /tmp/ folder
IncludeFile "continate.pb"
Procedure LeakSomething()
  Continate(#memory,"LeakSomething Start")
  AllocateMemory(10*1024)
  Continate(#memory,"LeakSomething Stop")
EndProcedure
For i=1 To 10
  LeakSomething()
Next
Includefile "continate.pb"

Code: Select all

;continate.pb
#Memory=1
#CPU=2
Procedure.l Continate(i.b=#Memory,name.s="")
  a.s="set pid to pidOfRunningApp("+Chr(34)+"PureBasic1"+Chr(34)+")"+#CRLF$
  a.s+"if pid is -1 then"+#CRLF$
  a.s+"	-- app is not running, so nothing to do"+#CRLF$
  a.s+"else"+#CRLF$
  a.s+"	set info to getProcessInfo(pid)"+#CRLF$
  a.s+"	if info is "+Chr(34)+""+Chr(34)+" then return"+#CRLF$
  a.s+"	return (round (first word of info as real)) & (round (second word of info as real))"+#CRLF$
  a.s+"end if"+#CRLF$
  a.s+"on fixLineEndings(str)"+#CRLF$
  a.s+"	set oldTIDs to AppleScript's text item delimiters"+#CRLF$
  a.s+"	set theLines to paragraphs of str"+#CRLF$
  a.s+"	set AppleScript's text item delimiters to ASCII character 10"+#CRLF$
  a.s+"	set fixedStr to theLines as string"+#CRLF$
  a.s+"	set AppleScript's text item delimiters to oldTIDs"+#CRLF$
  a.s+"	return fixedStr"+#CRLF$
  a.s+"end fixLineEndings"+#CRLF$
  a.s+"on getProcessInfo(pid)"+#CRLF$
  a.s+"	set perlCode to fixLineEndings("+Chr(34)+#CRLF$
  a.s+"open(PS, \"+Chr(34)+"/bin/ps -p "+Chr(34)+" & pid & "+Chr(34)+" -o pid,rss,%cpu |\"+Chr(34)+");"+#LF$
  a.s+"while (<PS>)"+#LF$
  a.s+"{"+#LF$
  a.s+"    if (/^\\s*"+Chr(34)+" & pid & "+Chr(34)+"\\s+(\\d+)\\s+([\\d.]+)\\s*$/)"+#LF$
  a.s+"    {"+#LF$
  a.s+"        my $rss = $1;"+#LF$
  a.s+"        my $cpu = $2;"+#LF$
  a.s+"        my $rssMB = sprintf(\"+Chr(34)+"%.1f\"+Chr(34)+", $rss / 1);"+#LF$
  a.s+"        print \"+Chr(34)+"$rssMB $cpu\"+Chr(34)+";"+#LF$
  a.s+"        last;"+#LF$
  a.s+"    }"+#LF$
  a.s+"}"+#LF$
  a.s+"close(PS);"+#LF$
  a.s+""+Chr(34)+")"+#LF$
  a.s+"	set info to do shell script "+Chr(34)+"perl -e "+Chr(34)+" & quoted form of perlCode"+#CRLF$
  a.s+"	return info"+#CRLF$
  a.s+"end getProcessInfo"+#CRLF$
  a.s+"on removeLastPart(str, delim)"+#CRLF$
  a.s+"	set oldTIDs to AppleScript's text item delimiters"+#CRLF$
  a.s+"	set AppleScript's text item delimiters to delim"+#CRLF$
  a.s+"	if (count str's text items) > 1 then"+#CRLF$
  a.s+"		set str to str's text 1 thru text item -2"+#CRLF$
  a.s+"	end if"+#CRLF$
  a.s+"	set AppleScript's text item delimiters to oldTIDs"+#CRLF$
  a.s+"	return str"+#CRLF$
  a.s+"end removeLastPart"+#CRLF$
  a.s+"on pidOfRunningApp(appName)"+#CRLF$
  a.s+"	tell application "+Chr(34)+"System Events"+Chr(34)+#CRLF$
  a.s+"		try"+#CRLF$
  a.s+"			set pid to the unix id of process appName"+#CRLF$
  a.s+"		on error"+#CRLF$
  a.s+"			set pid to -1"+#CRLF$
  a.s+"		end try"+#CRLF$
  a.s+"	end tell"+#CRLF$
  a.s+"	return pid"+#CRLF$
  a.s+"end pidOfRunningApp"+#CRLF$
  ret.l=Val(StringField(COCOA_AppleScript(a.s),i.b," "))
  If name.s
    fil.l=OpenFile(#PB_Any, GetTemporaryDirectory()+"memory.csv")    ; opens an existing file or creates one, if it does not exist yet
    If fil.l
      FileSeek(fil, Lof(fil))         ; jump to the end of the file (result of Lof() is used)
      WriteStringN(fil, FormatDate("%yyyy-%mm-%dd %hh:%ii",Date())+Chr(9)+name+Chr(9)+Str(ret.l))
      CloseFile(fil)
    EndIf
  EndIf
  ProcedureReturn ret.l
EndProcedure
Edit: Credit to original author: http://hayne.net/MacDev/AppleScript/app ... pplescript

Re: Finding leaking memory - what function to use?

Posted: Thu Mar 29, 2012 10:41 am
by jesperbrannmark
(continate was just the opposite of incontinate - so the opposite of leaking.. i dont know if there is such a word or thing.. probably not)

Re: Finding leaking memory - what function to use?

Posted: Sat Mar 31, 2012 10:56 pm
by Shardik
jesperbrannmark wrote:Is there a function to return the amount of memory used by the program as a integer?
Try my procedure GetUsedMemory(). It's called from a window timer
every second and displays the program's memory usage in a small
window. The integer value in bytes returned from GetUsedMemory()
is converted to MB and displayed as a string with StrF and one digit
behind the decimal point. So you have the direct comparison to the
value displayed in the activity monitor.

You have to compile my code example to an app and start this app
together with the activity monitor. The running app should display
the same memory usage as the activity monitor... :wink:

I think the call of a mach kernel function is a much more appropriate
method to obtain the memory usage of a program than your lengthy
Applescript... :twisted:

Code: Select all

EnableExplicit

#TASK_BASIC_INFO_32 = 4

ImportC ""
  mach_task_self()
  task_info(TaskPort.I, InformationType.I, *TaskInfo, *BufferSize)
EndImport

Structure time_value
  Seconds.I
  Microseconds.I
EndStructure

Structure task_basic_info
  suspend_count.I
  virtual_size.I
  resident_size.I
  user_time.time_value
  system_time.time_value
  policy.I
EndStructure

Procedure.I GetUsedMemory()
  Protected TaskInfo.task_basic_info
  Protected TaskInfoSize.I
  Protected TaskPort.I

  TaskPort = mach_task_self()
  TaskInfoSize = SizeOf(task_basic_info)
  
  If task_info(TaskPort, #TASK_BASIC_INFO_32, @TaskInfo, @TaskInfoSize) = 0
    ProcedureReturn TaskInfo\resident_size
  EndIf

  ProcedureReturn
EndProcedure

Define i.I

OpenWindow(0, 270, 100, 170, 40, "Memory usage")
TextGadget(0, 10, 10, WindowWidth(0) - 20, 20, "", #PB_Text_Center)
SetGadgetText(0, StrF(GetUsedMemory() / 1048576, 1) + " MB")
AddWindowTimer(0, 0, 1000)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Timer
      SetGadgetText(0, StrF(GetUsedMemory() / 1048576, 1) + " MB")
  EndSelect
ForEver

RemoveWindowTimer(0, 0)