MDCT Posted November 14, 2011 Share Posted November 14, 2011 (edited) Hello guys and gals, I had been searching and reading the forum about memory leak, but couldn't find anything related. So, I'm sorry if this has been answered before. I have a simple function, but somehow it keeps eating RAM little by little. I will explain it more after the Code. For $i=1 to 2 step 0 Sleep(150) $Result=_Check() ;~ ConsoleWrite($Result&@CRLF) Next Func _Check() Dim $Mpos, $hPoint, $FPointWinTitle $Mpos=MouseGetPos() $hPoint = DllCall("User32.dll", "hwnd", "WindowFromPoint", "int", $Mpos[0], "int", $Mpos[1]) $FPointWinTitle=DllCall("user32.dll", "int", "GetWindowText", "hwnd", $hPoint[0], "str", "", "int", 32768) return $FPointWinTitle[2] EndFunc As you can see, it mostly does dllcalls on user32 'WindowFromPoint' and 'GetWindowText'. In the test on my PC, the script would take around 4-16kb if a new window appears. However, slowly it will become less aggressive when no new window appears, but it still eats a bit here and there. Now, the leak is gone if I take out 'GetWindowText', so the script only calls 'WindowFromPoint'. Can someone please tell me this is a memory leak or not, and how to make the memory stable? Thank you. PS: Oh, almost forgot, I know one way to patch the memory leak using 'EmptyWorkingSet'. But I believe it's not really a fix. So, I'm hoping to find the right fix. Edited November 14, 2011 by MDCT Link to comment Share on other sites More sharing options...
guinness Posted November 14, 2011 Share Posted November 14, 2011 (edited) Personally I would just use _WinAPI_GetWindowText & _WinAPI_WindowFromPoint in WinAPI.au3 as looking at your DLL calls they're not geared up for x64. Edited November 14, 2011 by guinness UDF List: _AdapterConnections() • _AlwaysRun() • _AppMon() • _AppMonEx() • _ArrayFilter/_ArrayReduce • _BinaryBin() • _CheckMsgBox() • _CmdLineRaw() • _ContextMenu() • _ConvertLHWebColor()/_ConvertSHWebColor() • _DesktopDimensions() • _DisplayPassword() • _DotNet_Load()/_DotNet_Unload() • _Fibonacci() • _FileCompare() • _FileCompareContents() • _FileNameByHandle() • _FilePrefix/SRE() • _FindInFile() • _GetBackgroundColor()/_SetBackgroundColor() • _GetConrolID() • _GetCtrlClass() • _GetDirectoryFormat() • _GetDriveMediaType() • _GetFilename()/_GetFilenameExt() • _GetHardwareID() • _GetIP() • _GetIP_Country() • _GetOSLanguage() • _GetSavedSource() • _GetStringSize() • _GetSystemPaths() • _GetURLImage() • _GIFImage() • _GoogleWeather() • _GUICtrlCreateGroup() • _GUICtrlListBox_CreateArray() • _GUICtrlListView_CreateArray() • _GUICtrlListView_SaveCSV() • _GUICtrlListView_SaveHTML() • _GUICtrlListView_SaveTxt() • _GUICtrlListView_SaveXML() • _GUICtrlMenu_Recent() • _GUICtrlMenu_SetItemImage() • _GUICtrlTreeView_CreateArray() • _GUIDisable() • _GUIImageList_SetIconFromHandle() • _GUIRegisterMsg() • _GUISetIcon() • _Icon_Clear()/_Icon_Set() • _IdleTime() • _InetGet() • _InetGetGUI() • _InetGetProgress() • _IPDetails() • _IsFileOlder() • _IsGUID() • _IsHex() • _IsPalindrome() • _IsRegKey() • _IsStringRegExp() • _IsSystemDrive() • _IsUPX() • _IsValidType() • _IsWebColor() • _Language() • _Log() • _MicrosoftInternetConnectivity() • _MSDNDataType() • _PathFull/GetRelative/Split() • _PathSplitEx() • _PrintFromArray() • _ProgressSetMarquee() • _ReDim() • _RockPaperScissors()/_RockPaperScissorsLizardSpock() • _ScrollingCredits • _SelfDelete() • _SelfRename() • _SelfUpdate() • _SendTo() • _ShellAll() • _ShellFile() • _ShellFolder() • _SingletonHWID() • _SingletonPID() • _Startup() • _StringCompact() • _StringIsValid() • _StringRegExpMetaCharacters() • _StringReplaceWholeWord() • _StringStripChars() • _Temperature() • _TrialPeriod() • _UKToUSDate()/_USToUKDate() • _WinAPI_Create_CTL_CODE() • _WinAPI_CreateGUID() • _WMIDateStringToDate()/_DateToWMIDateString() • Au3 script parsing • AutoIt Search • AutoIt3 Portable • AutoIt3WrapperToPragma • AutoItWinGetTitle()/AutoItWinSetTitle() • Coding • DirToHTML5 • FileInstallr • FileReadLastChars() • GeoIP database • GUI - Only Close Button • GUI Examples • GUICtrlDeleteImage() • GUICtrlGetBkColor() • GUICtrlGetStyle() • GUIEvents • GUIGetBkColor() • Int_Parse() & Int_TryParse() • IsISBN() • LockFile() • Mapping CtrlIDs • OOP in AutoIt • ParseHeadersToSciTE() • PasswordValid • PasteBin • Posts Per Day • PreExpand • Protect Globals • Queue() • Resource Update • ResourcesEx • SciTE Jump • Settings INI • SHELLHOOK • Shunting-Yard • Signature Creator • Stack() • Stopwatch() • StringAddLF()/StringStripLF() • StringEOLToCRLF() • VSCROLL • WM_COPYDATA • More Examples... Updated: 22/04/2018 Link to comment Share on other sites More sharing options...
MDCT Posted November 14, 2011 Author Share Posted November 14, 2011 (edited) #include <winapi.au3> For $i=1 to 2 step 0 Sleep(150) $Result=_Check() ConsoleWrite($Result&@CRLF) Next Func _Check() Dim $Struct, $hPoint, $FPointWinTitle $Struct = DllStructCreate($tagPoint) DllStructSetData($Struct, "x", MouseGetPos(0)) DllStructSetData($Struct, "y", MouseGetPos(1)) $hPoint = _WinAPI_WindowFromPoint($Struct) $FPointWinTitle=_WinAPI_GetWindowText($hPoint) return $FPointWinTitle EndFunc Thank you for the suggestion, I tried using '_WinAPI_GetWindowText' and '_WinAPI_WindowFromPoint' from winapi.au3 but it is still taking more and more memory. Edited November 14, 2011 by MDCT Link to comment Share on other sites More sharing options...
trancexx Posted November 14, 2011 Share Posted November 14, 2011 Hm, I can't see any leak with that code. What version of AutoIt do you use? ♡♡♡ . eMyvnE Link to comment Share on other sites More sharing options...
MDCT Posted November 14, 2011 Author Share Posted November 14, 2011 (edited) I'm using version 3.3.6.1. The leak doesn't happen if I use only 'WindowFromPoint'. I tried dllcall 'GetClassName', it's also doing the same thing.It takes RAM mostly when new window is created or new window is active, and sometimes switching between windows, otherwise it is stable. With only 'WindowFromPoint', my script is stable.Does it happen only on my PC? Edited November 14, 2011 by MDCT Link to comment Share on other sites More sharing options...
trancexx Posted November 14, 2011 Share Posted November 14, 2011 It's hard to say. I don't remember seeing anyone having the issue you describe. What's your system? ♡♡♡ . eMyvnE Link to comment Share on other sites More sharing options...
MDCT Posted November 14, 2011 Author Share Posted November 14, 2011 Hi trancexx, thank you for trying to help me. My system is WIN XP on Pentium-4 3.00GHz with 1Gig of RAM. I have tried on different PC, but it also keeps taking up RAM as I open new program with window. The fact that with just 'WindowFromPoint' the script doesn't keep consuming RAM as 'GetWindowText' or 'GetClassName', makes me think perhaps this is a normal behavior of using those dllcall. As you can see I even use local variables so it will keep removing the past results, thinking that it could help with the RAM. I hope there's a solution for this "unwanted" behavior, perhaps like running the script on RAM and release all the used RAM after getting the result...this, in my opinion, is better than using 'EmptyWorkingSet'. Link to comment Share on other sites More sharing options...
trancexx Posted November 14, 2011 Share Posted November 14, 2011 How do you verify RAM usage? What OS was running on different PC? What AutoIt was running on different PC? ♡♡♡ . eMyvnE Link to comment Share on other sites More sharing options...
Bert Posted November 14, 2011 Share Posted November 14, 2011 Try this: %windir%system32rundll32.exe advapi32.dll,ProcessIdleTasks The Vollatran project My blog: http://www.vollysinterestingshit.com/ Link to comment Share on other sites More sharing options...
MDCT Posted November 14, 2011 Author Share Posted November 14, 2011 (edited) trancexx,1. I verify RAM usage by using TaskManager, the 'Mem Usage' column.2. The different PC was running WIN XP SP2 the same with what I'm using.3. No Autoit was running on different PC, I was just running the compiled version of the above code.Hmm...as a matter of fact, on the PC that I'm using, I use the 'Self Extracting Archive' version of Autoit, the one that I don't have to install (I try to reduce information being add to the system). However, I doubt this is the case tho, or is it??Hi MPH,Thanks for the suggestion. I don't know if this is just my feeling or not..but it seems the leak is getting a bit smaller. Now it doesn't always take RAM immediately after new window shows up. However, it is still taking RAM.When I started the app, it used 3,996k. After opening new programs (Notepad, Regedit, Firefox, MsPaint, Onscreen Keyboard, control panels applets, etc.) and closing their windows, the script used RAM at 4,248k. And, after I wrote this reply, now it is at 4,280k.Edit:Just did a bit of experiment. With just 'WindowFromPoint' the usage is stable at 3,924k.Now, I remove the 'WindowFromPoint' and set the handle at 0 for the 'GetWindowText' to get the text. It started at 3,952k then after I opened some windows it became 3,964kb and it stays stable at that.Now, I set the handle for active window (WingetHandle("[Active]")) and the leak is back.It makes me think, probably, the memory leak that I'm experiencing is caused by the length of the results (texts) that are different from each new window. Edited November 14, 2011 by MDCT Link to comment Share on other sites More sharing options...
Shaggi Posted November 14, 2011 Share Posted November 14, 2011 (edited) who knows how autoit allocates memory... if its a critical piece of code, i would suggest you allocate it yourself, maybe? Local $aRet = DllCall("User32.dll","int","GetWindowTextLengthW","hwnd",$hWnd) Local $nChars = $aRet[0] Local $bBuf = DllStructCreate("wchar[" & $hChars + 2 & "]") ;Remember null $aRet = DllCall("User32.dll","int","GetWindowTextLengthW","hwnd",$hWnd,"ptr",DllStructGetPtr($bBuf),"int",$nChars+1) Local $szWindowText = DllStructGetData($Buf,1) PS: Oh, almost forgot, I know one way to patch the memory leak using 'EmptyWorkingSet'. But I believe it's not really a fix. So, I'm hoping to find the right fix.nonono, dont do this Edited November 14, 2011 by Shaggi Ever wanted to call functions in another process? ProcessCall UDFConsole stuff: Console UDFC Preprocessor for AutoIt OMG Link to comment Share on other sites More sharing options...
MDCT Posted November 15, 2011 Author Share Posted November 15, 2011 Hi Shaggi, Thank you for the suggestion. Did you mean like this? For $i=1 to 2 step 0 Sleep(150) $Result=_Check() ;~ ConsoleWrite($Result&@CRLF) Next Func _Check() Local $Mpos=MouseGetPos() Local $hPoint = DllCall("User32.dll", "hwnd", "WindowFromPoint", "int", $Mpos[0], "int", $Mpos[1]) Local $aRet = DllCall("User32.dll","int","GetWindowTextLengthW","hwnd",$hPoint[0]) Local $nChars = $aRet[0] Local $bBuf = DllStructCreate("wchar[" & $nChars + 2 & "]") ;Remember null $aRet = DllCall("User32.dll","int","GetWindowTextW","hwnd",$hPoint[0],"ptr",DllStructGetPtr($bBuf),"int",$nChars+1) Local $szWindowText = DllStructGetData($bBuf,1) return DllStructGetData($bBuf,1) EndFunc Unfortunately, it still leaks. It started with 3,830, then after some opening and switching windows it became 4,224kb. And why using 'EmptyWorkingSet' is bad? If I only use local variables in a function, there should be no un-useful information stored (as at the end of the function those variables are discarded), and maybe the increase in RAM usage is because of the increasing WorkingSet itself...so maybe the real fix is to use 'EmptyWorkingSet', no? If someone could enlighten me, I would very much appreciate it. Does anyone have any other suggestions? Link to comment Share on other sites More sharing options...
Shaggi Posted November 15, 2011 Share Posted November 15, 2011 Hi Shaggi, Thank you for the suggestion. Did you mean like this? For $i=1 to 2 step 0 Sleep(150) $Result=_Check() ;~ ConsoleWrite($Result&@CRLF) Next Func _Check() Local $Mpos=MouseGetPos() Local $hPoint = DllCall("User32.dll", "hwnd", "WindowFromPoint", "int", $Mpos[0], "int", $Mpos[1]) Local $aRet = DllCall("User32.dll","int","GetWindowTextLengthW","hwnd",$hPoint[0]) Local $nChars = $aRet[0] Local $bBuf = DllStructCreate("wchar[" & $nChars + 2 & "]") ;Remember null $aRet = DllCall("User32.dll","int","GetWindowTextW","hwnd",$hPoint[0],"ptr",DllStructGetPtr($bBuf),"int",$nChars+1) Local $szWindowText = DllStructGetData($bBuf,1) return DllStructGetData($bBuf,1) EndFunc Unfortunately, it still leaks. It started with 3,830, then after some opening and switching windows it became 4,224kb. And why using 'EmptyWorkingSet' is bad? If I only use local variables in a function, there should be no un-useful information stored (as at the end of the function those variables are discarded), and maybe the increase in RAM usage is because of the increasing WorkingSet itself...so maybe the real fix is to use 'EmptyWorkingSet', no? If someone could enlighten me, I would very much appreciate it. Does anyone have any other suggestions? Its a bad practice because you are abstracting from the real problem, your program leaking. Btw any reason you dont use WinGetText()? I tested the code and i experience no leaks, whatsoever. I dont think it's a problem with the code but maybe the enviroment you're using it in... Remember other processes in your system can potentially create memory leaks in your program. Antivirus and antimalware programs also liberally inject themselves into other processes. Lastly, when you say memoryleak, would the code potentially leak 100 if not 1000 of megabytes? If we are talking small jumps < 10 mb, this is not the problem. Ever wanted to call functions in another process? ProcessCall UDFConsole stuff: Console UDFC Preprocessor for AutoIt OMG Link to comment Share on other sites More sharing options...
MDCT Posted November 15, 2011 Author Share Posted November 15, 2011 Its a bad practice because you are abstracting from the real problem, your program leaking. Btw any reason you dont use WinGetText()?Because WinGetText() is slower than dllcall. On my PC 'GetWindowText' it is around 20x faster. And I want to put as many sleep as possible to reduce CPU while maintaining the script's resposiveness.I tested the code and i experience no leaks, whatsoever. I dont think it's a problem with the code but maybe the enviroment you're using it in... Remember other processes in your system can potentially create memory leaks in your program. Antivirus and antimalware programs also liberally inject themselves into other processes.Lastly, when you say memoryleak, would the code potentially leak 100 if not 1000 of megabytes? If we are talking small jumps < 10 mb, this is not the problem.Ahhh...now I see. Maybe I was being too bitchy about the RAM consumption, because I was comparing it with 'WindowFromPoint'. With only 'WindowFromPoint' the script doesn't take any additional RAM at all. With 'GetWindowText' it takes mostly 4,000-16,000 byte almost constantly each time I open a new window, so it's still a long way to reach 10mb..maybe in days it will reach that.This is not a leak then, so 'EmptyWorkingSet' after some times is ok I reckon, just to keep the Mem usage from increasing in time. And for my own personal reference, I will keep in mind that environment could cause my script to leak.Thank you Shaggi for your information and help. Link to comment Share on other sites More sharing options...
Shaggi Posted November 15, 2011 Share Posted November 15, 2011 (edited) Because WinGetText() is slower than dllcall. On my PC 'GetWindowText' it is around 20x faster. And I want to put as many sleep as possible to reduce CPU while maintaining the script's resposiveness. Ahhh...now I see. Maybe I was being too bitchy about the RAM consumption, because I was comparing it with 'WindowFromPoint'. With only 'WindowFromPoint' the script doesn't take any additional RAM at all. With 'GetWindowText' it takes mostly 4,000-16,000 byte almost constantly each time I open a new window, so it's still a long way to reach 10mb..maybe in days it will reach that. This is not a leak then, so 'EmptyWorkingSet' after some times is ok I reckon, just to keep the Mem usage from increasing in time. And for my own personal reference, I will keep in mind that environment could cause my script to leak. Thank you Shaggi for your information and help. Its still weird though, if this is the only code you use... Anyway, if speed is so crucial that the inbuilt functions in autoit is not quick enough, you might want to consider another language? heres the example in c++, not so much different - and a lot quicker: #include <Windows.h> #include <string> #include <iostream> std::string _Check(); int main(int argc, char ** argv) { std::string result; while (true) { result = _Check(); std::cout << result; Sleep(150); } return 0; } std::string _Check() { HWND hWnd; POINT mPos; GetMousePos(&mPos); hWnd = WindowFromPoint(mPos); int nLen = GetWindowTextLengthA(hWNd); char * txtbuffer = new char[nLen + 1]; GetWindowTextA(hWnd,txtbuffer,nLen+1); std::string ret(txtbuffer); delete [] txtbuffer; return ret; } Edited November 16, 2011 by Shaggi Ever wanted to call functions in another process? ProcessCall UDFConsole stuff: Console UDFC Preprocessor for AutoIt OMG Link to comment Share on other sites More sharing options...
MDCT Posted November 16, 2011 Author Share Posted November 16, 2011 (edited) It is very weird, Shaggi. I even tried on different AutoIt script that has nothing to do with dllcall 'GetWindowText', and it was also taking 4kb-16kb mostly when a new window is activated. It looks like the Autoit's engine is dependent on windows creations or something. Below is the sample script that I use: #include #include #include Dim $item[6] GUICreate("listview items", 300, 200, -1, -1, -1, $WS_EX_ACCEPTFILES) $listview = GUICtrlCreateListView("col1 |col2 |col3 ", 10, 10, 200, 150, -1, $LVS_EX_CHECKBOXES) $button = GUICtrlCreateButton("Get What Names Are Checked?", 75, 170, 170, 20) $item[1] = GUICtrlCreateListViewItem("item1|col22|col23", $listview) $item[2] = GUICtrlCreateListViewItem("item2|col12|col13", $listview) $item[3] = GUICtrlCreateListViewItem("item3|c3332|col33", $listview) $item[4] = GUICtrlCreateListViewItem("item4|44444|col33", $listview) $item[5] = GUICtrlCreateListViewItem("item5|5555|col33", $listview) GUISetState() Do $msg = GUIGetMsg() Select Case $msg = $button For $x = 1 To 5 If _GUICtrlListView_GetItemChecked($listview, $x - 1) Then MsgBox(0, "listview item", _GUICtrlListView_GetItemTextString($listview, $x - 1) & " " & @CRLF & "Line Checked = " & $x, 2) EndIf Next Case $msg = $listview MsgBox(0, "listview", "clicked=" & GUICtrlGetState($listview), 2) EndSelect Until $msg = $GUI_EVENT_CLOSEAs you can see, it's just a normal listview script. I ran the script from SciTe, switched between windows, opened new windows....and if you look at the TaskMan, you will see the RAM usage is increasing little by little eventhough the script has nothing to do with window switchings or creations. I was thinking to create an app that will be run 24/7 on my PC (mostly restart every 3 weeks) so I want to create applications that are efficient in RAM, CPU and speed wise in order for the app not to slow things down. I have spent hours reading the forum and doing many experiments to find the best commands or functions for my apps. Constant RAM eating on most Autoit scripts eventho small makes me a bit dissapointed. I guess I should use Autoit to create scripts that are not to be used 24/7 as Autoit scripts tend to consume additional memory over time. Also, I just read from the net: Memory leaks are a common error in programming, especially when using languages that have no built-in automatic garbage collection, such as C and C++. So, yeah, I guess C++ is the way to go for my 24/7 app, Shaggi. The C++ example doesn't look that different but it looks quite confusing for now. Thank you so much for your help and suggestions, Shaggi. Take care. PS: On second thought..maybe it's a good idea to ask Autoit gods or goddesses about this behavior first. Edited November 16, 2011 by MDCT Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now