The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: NoCforMe on October 23, 2011, 03:00:17 AM

Title: How to avoid leaky Windows programs
Post by: NoCforMe on October 23, 2011, 03:00:17 AM
I know it's possible to create Windows apps that "leak" memory (i.e., allocate memory but don't deallocate it on exit), and I want to avoid this problem, of  course.

Up to now I've been pretty much breezily going on the assumption that all of the objects I create (mostly handles, to brushes, windows, etc.) will be automagically deallocated upon exit. I am careful to deallocate explicitly allocated memory (i.e., using GlobalAlloc() ). But is this correct?

I know it's probably a big question, possibly a big can of worms, but are there any (more or less) simple guidelines as to what objects one needs to destroy or deallocated before exiting a program?

Thanks especially to any Windoze experts who may happen to wander by here ...
Title: Re: How to avoid leaky Windows programs
Post by: jj2007 on October 23, 2011, 03:31:11 AM
> will be automagically deallocated upon exit
That is the Common Wisdom, although MSDN is somewhat half-baken about it, documentation-wise. I have had several occasions where after allocating a lot of heap mem (>500 MB) and exiting with a crash, the whole system was so slow that I had to reboot.
If you want to test it, write a proggie that misbehaves, and launch it a thousand times. Report what happens :bg
Title: Re: How to avoid leaky Windows programs
Post by: dedndave on October 23, 2011, 03:59:11 AM
allocated memory is easy to understand
if you allocate it - free it when done
a similar statement can be made for file handles, of course

the stack space you use - don't worry about it - ExitProcess releases it for you

beyond that, i suggest you carefully read the documentation for each function you use that returns a handle
in many cases, destroying the window releases the handles
in some cases, it does not
font handles come to mind - they usually need to be deleted  :P

brush handles - it depends on how it is created and used

for example, if you get a handle to a stock object (GetStockObject),
the handle does not need to be deleted, but there is no harm in doing so

if you use a system color in WNDCLASSEX (the first 19 values or NULL) - RegisterClassEx accepts an index - no handle to delete
if you use a system color above the first 19 (CreateSolidBrush), it should be deleted
if you use the same brushes by obtaining a handle during WM_PAINT (GetSysColorBrush), you must not delete it

menu handles are on and off, too - lol
if the menu handle is set to a window (SetMenu), the handle does not need to be destroyed
otherwise, it should be

the point is - each case is different, and you have to do a little research and reading
Title: Re: How to avoid leaky Windows programs
Post by: NoCforMe on October 23, 2011, 04:15:50 AM
OK, I went back and checked, and the description of CreateFont() does say, in the Remarks section:

Quote
When you no longer need the font, call the DeleteObject function to delete it.

so that does seem like a Good Idea. However, it seems there are a lot of murky cases where MSDN doesn't really make it clear whether or not you are supposed to destroy/delete/deallocate the object.

Further research is called for.
Title: Re: How to avoid leaky Windows programs
Post by: dedndave on October 23, 2011, 04:18:59 AM
you get a lot of info of this kind by reading the general catagory docs
like the About Menus, Using Menus, Using Brushes, etc - those sections

also - read the sections about creating windows
and - the DestroyWindow function probably has some info
Title: Re: How to avoid leaky Windows programs
Post by: hutch-- on October 23, 2011, 04:27:16 AM
Apply the law of gravity, what goes up must come down. You can be sloppy with simple stuff and it gets recovered on exit but get used to deallocating memory that you allocate once you have finished with it or it can come back and bite you when you least expect it.
Title: Re: How to avoid leaky Windows programs
Post by: jj2007 on October 23, 2011, 06:31:25 AM
The recommendations on DeleteObject refer to running processes. If you create fresh brushes in a WM_MOVE handler, then after some hours the user might get new experiences indeed. But quitting the app is a different case.

> The ExitProcess function in the __except block automatically releases virtual memory allocations

The Master's Voice (http://msdn.microsoft.com/en-us/library/aa366803%28v=VS.85%29.aspx)... I am pretty sure that all those cute fonts and brushes and controls etc reside somewhere in the heap and get discarded with ExitProcess. The question is what happens if you exit the process your own wayTM (and NoCforMe has repeatedly indicated that he wants to do everything his own way :green2)
Title: Re: How to avoid leaky Windows programs
Post by: ToutEnMasm on October 23, 2011, 06:43:02 AM

If you want to be sure that all  is free , put a zero on all variables with a free hAndle.
On exit , verify that all variables with an handle have  zero value.
Doing this , you win another advantage in complex loop.Is it done ?,look the value of handle values,if it is zero,you have to init them.
You can also group them in data.
Title: Re: How to avoid leaky Windows programs
Post by: NoCforMe on October 23, 2011, 07:06:34 AM
Quote from: jj2007 on October 23, 2011, 06:31:25 AM
> The ExitProcess function in the __except block automatically releases virtual memory allocations

The Master's Voice (http://msdn.microsoft.com/en-us/library/aa366803%28v=VS.85%29.aspx)... I am pretty sure that all those cute fonts and brushes and controls etc reside somewhere in the heap and get discarded with ExitProcess. The question is what happens if you exit the process your own wayTM (and NoCforMe has repeatedly indicated that he wants to do everything his own way :green2)


Well, while that may be true (and don't we all here have our various idiosyncrasies for that matter?), I do use ExitProcess() to bring the whole thing to a screeching halt. How else would you do it?



start:
INVOKE GetModuleHandle, NULL
MOV InstanceHandle, EAX

INVOKE WinMain, EAX
INVOKE ExitProcess, EAX



Which I copied out of the MASM32 example programs.

Title: Re: How to avoid leaky Windows programs
Post by: jj2007 on October 23, 2011, 09:13:56 AM
Quote from: NoCforMe on October 23, 2011, 07:06:34 AM...use ExitProcess() to bring the whole thing to a screeching halt. How else would you do it?

Ask Dave for his favourite exception :bg
Title: Re: How to avoid leaky Windows programs
Post by: dedndave on October 23, 2011, 10:00:53 AM
 :bdg
not just my favourite - everyones favourite is c0000005 - access violation   :bg
when i started out, i considered changing my forum nic to c0000005 - lol

JJ's msdn link is a good one
i found another....
http://msdn.microsoft.com/en-us/library/ms859400.aspx

and i found a couple programs
these programs may not detect all leaks, but can be helpful
http://winleak.sourceforge.net/
http://www.runtimechecker.com/

haven't tried the first one - but i will play with it
the second one - i have used it
it basically checks to see if you've crossed all your T's and dotted all your I's
Title: Re: How to avoid leaky Windows programs
Post by: jj2007 on October 23, 2011, 04:12:35 PM
Quote from: dedndave on October 23, 2011, 10:00:53 AM
i found another....
http://msdn.microsoft.com/en-us/library/ms859400.aspx

"Typically, the operating system can clean up after a program which leaks memory after it terminates."

But: expected != observed behaviour :naughty:
Title: Re: How to avoid leaky Windows programs
Post by: dedndave on October 23, 2011, 04:15:46 PM
that's for sure - lol

Quote"Typically, the operating system can clean up after a program which leaks memory after it terminates."

they must be talking about some OS other than windows   :lol
Title: Re: How to avoid leaky Windows programs
Post by: redskull on October 23, 2011, 04:45:21 PM
You are really talking about two different things: executive objects and virtual memory.  Whenever a process ends, all it's memory is freed and given back to the system; since the process heap exists in the process memory, there is no worry about leaking that (i.e. VirtualAlloc, HeapAlloc, GlobalAlloc, etc).

Executive objects, basically anything that you have to create via a function and access via a HANDLE (fonts, mutexes, files, etc), are managed by the operating system; that's why you have to access them indirectly using a handle, and not directly via a pointer.  Objects that exist in the system are reference counted by the kernel, and remain active until all the processess using them no longer do so.

However, each process keeps a list of all the handles a particular process has opened (0x0dc in the EPROCESS block).  Part of the shutdown that happens when your process ends is that these still-open handles are closed, so generally speaking, any memory those objects are taking up will not leak.  That being said, however, certain objects are 'permenent'; they are not reference counted and will stay active until you explicity release them.  I can't recall exactly which ones are, but there is an OBJ_PERMANANT attribute you can check to see.  IIRC, these are few and far between.

All that aside, however, delete stuff when you no longer need it.  Just because it will probably get freed when you end your process doesn't mean it won't have negative affects while you ARE executing; each object you create still tags YOUR memory usage quota.  If you leave outstanding objects created, then you will take more paging hits, etc. 

But in the end, it's just bad programming: clean up your own mess.

-r
Title: Re: How to avoid leaky Windows programs
Post by: jj2007 on October 23, 2011, 05:27:13 PM
Quote from: redskull on October 23, 2011, 04:45:21 PM
You are really talking about two different things: executive objects and virtual memory.  Whenever a process ends, all it's memory is freed and given back to the system; since the process heap exists in the process memory, there is no worry about leaking that (i.e. VirtualAlloc, HeapAlloc, GlobalAlloc, etc).

red,
I wish this were true, but my experience says if you crash your app, you will have to reboot to make your system fast again - Win XP SP3.
Re bad programming habits: if there is a clear documentation saying ExitProcess does all the cleanup, then it is bad programming to do the same before ExitProcess. Nonetheless the Exit (uppercase E...) macro of MasmBasic cleans all allocated memory and closes all open filehandles. Precisely because the documentation is so lousy, and because my experience says don't trust the OS.
Title: Re: How to avoid leaky Windows programs
Post by: NoCforMe on October 23, 2011, 07:49:16 PM
Quote from: jj2007 on October 23, 2011, 05:27:13 PM
Re bad programming habits: if there is a clear documentation saying ExitProcess does all the cleanup, then it is bad programming to do the same before ExitProcess.

At the very least it would seem to be redundant programming practice to do so ... why do something that's already done?
Title: Re: How to avoid leaky Windows programs
Post by: redskull on October 23, 2011, 08:32:08 PM
Quote from: NoCforMe on October 23, 2011, 07:49:16 PM
At the very least it would seem to be redundant programming practice to do so ... why do something that's already done?

So then I suppose putting airbags in cars absolves you of the responsibility of driving safely?   :wink 

The reason is that you don't know when, or even if, your program will ever end.  The user is well within his rights to leave it running all day, every day, which means all the resources you are sucking up are both unavailable to other programs, as well as hurting your quotas.  Your program should use what it needs, when it needs it, and nothing else.  Imagine the nightmare if every program grabbed all the resources it thinks it might ever need, and never let them go...

-r
Title: Re: How to avoid leaky Windows programs
Post by: NoCforMe on October 23, 2011, 08:45:12 PM
Hmm, point taken. I would then amend my approach to say that one should release  any significant resources that are no longer needed (mainly large chunks of memory). I still wouldn't worry much about a few handles to objects. Now, if your program were to use hundreds or thousands of such objects, that might be a different story, and it might be a Good Idea to release the unused ones.
Title: Re: How to avoid leaky Windows programs
Post by: hutch-- on October 23, 2011, 09:21:19 PM
Roughly, catchalls, error handlers for non critical hardware tasks and the like are just sloppy programming. Our friend may like the idea of NO C FOR ME but with an operating system based on C and later C++ you either do it the right way or end up writing crap that is unreliable. Really what some of you guys need is to write 16 bit Windows code where one mistake took the OS and every other running app down.

Memory allocation, high level resource usage and the like have de-allocation routines for a reason, they are not there to just to be  ignored. The simple test is to run task manager and if your memory usage keeps going up, you have a leak from failing to release a resource or de-allocate memory.

At the stage of ExitProcess() your application should have the same resource/memory usage that it had at startup, if not you need to fix it.
Title: Re: How to avoid leaky Windows programs
Post by: fearless on October 23, 2011, 10:07:15 PM
Quote from: hutch-- on October 23, 2011, 09:21:19 PMThe simple test is to run task manager and if your memory usage keeps going up, you have a leak from failing to release a resource or de-allocate memory.

So true. That happened to me recently with my memory leak from STM_SETIMAGE - http://www.masm32.com/board/index.php?topic=17270.msg144769#msg144769 and i used task manager to identify if i had an issue.
Title: Re: How to avoid leaky Windows programs
Post by: redskull on October 23, 2011, 11:53:02 PM
Quote from: hutch-- on October 23, 2011, 09:21:19 PM
Really what some of you guys need is to write 16 bit Windows code where one mistake took the OS and every other running app down.

Did you walk uphill through the snow, both ways, to get to that Win16 box?  :toothy

But in response to the suggestion that only "significant" resources get deallocated, who determines that?  If your program occasionally uses a file, is it okay to keep that object allocated, locking every other program out from using it for the duration?  If your program occasionally listens on port 80, is it okay to usurp that socket from any other application?  There are more resources than just memory, and more significance than just size.

-r
Title: Re: How to avoid leaky Windows programs
Post by: hutch-- on October 24, 2011, 12:23:22 AM
 :bg

Red,

Just about, something these young fellas missed out on was software simulated multitasking where all of Windows was one big unhappy app, one blunder and you bypassed the BLUE screen of death and went directly to the BLACK screen of death that did not even have text on it. One learnt GlobalFree() by heart in those days, you got a little time with forgetting to free a brush before it all locked up and the OS stopped.

On the UP side, Windows 3.?? used to boot much faster than the later 32 bit versions so it was not as big a deal.
Title: Re: How to avoid leaky Windows programs
Post by: dedndave on October 24, 2011, 12:25:04 AM
Quote...the BLACK screen of death that did not even have text on it
i remember those   :bg
if you were lucky, you had a blinking cursor in the upper left hand corner
Title: Re: How to avoid leaky Windows programs
Post by: Gunner on October 24, 2011, 01:17:15 AM
If you allocate memory, create a font, brush, gdi object, or other system resource.  Just free/delete it when done, that is good programming practice.
Title: Re: How to avoid leaky Windows programs
Post by: MichaelW on October 24, 2011, 05:45:21 AM
I recall reading in the Microsoft documentation about limited resources that you "must" release when you finish using then. ATM the only one that comes to mind is common DCs:

http://msdn.microsoft.com/en-us/library/dd183571(v=VS.85).aspx

So I decided do an experiment to see what the effects of not releasing a large number of common DCs would be. My test code:

;==============================================================================
include \masm32\include\masm32rt.inc
;==============================================================================
    .data
        hwndStatic  dd 0
        hFile       dd 0
        dcCount     dd 0
    .code
;==============================================================================

DialogProc proc hwndDlg:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

    SWITCH uMsg

        CASE WM_INITDIALOG
       
            mov hFile, fopen("testlog.txt")
            .IF hFile == INVALID_HANDLE_VALUE
                  mov hFile, fcreate("testlog.txt")
            .ENDIF
            mov eax, fseek(hFile,0,END)

            invoke GetTickCount
            push eax

            ID=1000
            REPEAT 1024

                invoke GetDlgItem, hwndDlg, ID
                mov hwndStatic, eax
                .IF eax == 0
                    fprintc hFile, chr$("GetDlgItem failed")
                    jmp @F
                .ENDIF

                ;-----------------------------------------------------
                ; Ensure that GetDC will return a common DC for the
                ; static control, instead of a private DC as it would
                ; be if the control had the CS_OWNDC class style.
                ;-----------------------------------------------------

                invoke GetClassLong, hwndStatic, GCL_STYLE
                .IF eax & CS_OWNDC
                    fprintc hFile, chr$("CS_OWNDC")
                    jmp @F
                .ENDIF

                invoke GetDC, hwndStatic
                .IF eax == NULL
                    fprintc hFile, cfm$("GetDC failed\n")
                    jmp @F
                .ENDIF

                inc dcCount
                ID=ID+1

            ENDM

          @@:

            fprintc hFile, sdword$(dcCount)
            fprintc hFile, chr$(9)
            invoke GetTickCount
            pop edx
            sub eax, edx
            fprintc hFile, sdword$(eax)
            fprintc hFile, chr$(13,10)

            fclose hFile

        CASE WM_COMMAND

            SWITCH wParam

                CASE IDCANCEL

                    invoke EndDialog, hwndDlg, NULL

            ENDSW

        CASE WM_CLOSE

            invoke EndDialog, hwndDlg, NULL
    ENDSW

    return 0

DialogProc endp

;==============================================================================
start:
;==============================================================================

    Dialog  "Test", \
            "MS Sans Serif",10, \
            WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \
            1024, \
            0,0,112,122, \
            1024*32

    X=0
    Y=0
    ID=1000
    REPEAT 32
        REPEAT 32
            DlgStatic 0,WS_BORDER,X,Y,2,2,ID
            X=X+3
            ID=ID+1
        ENDM
        X=0
        Y=Y+3
    ENDM

    invoke GetModuleHandle, NULL
    CallModalDialog eax, 0, DialogProc, NULL
    exit
;==============================================================================
end start


To get representative times in the log file you must wait for the dialog to be fully displayed before you start another instance of the app.

And here is the log file for a test under Windows 2000 where I continued starting new instances until there was obviously a problem.

1024 330
1024 802
1024 1402
1024 2113
1024 2884
1024 3695
1024 4517
1024 5328
1024 6129
1024 6910
1024 7681
1024 8482
1024 9294
GetDC failed
607 5908


Somewhere around the point where GetDC failed, and at ~13K unreleased common DCs, the desktop stopped refreshing correctly. Surprising to me, after I closed all of the running instances everything returned to normal, as near as I can tell by just using the system.

Edit: I forgot to add that I had run the app something like 100 times prior to the test that failed, without any sign of a problem, and I had previously had more than 20 instances running, but at that point I was still chasing bugs so I was building it as a console app.

Edit2: It doesn't always fail at the same point. Here are the results for another trial:

1024 271
1024 701
1024 1272
1024 1923
1024 2674
1024 3655
1024 4537
1024 5518
1024 6780
1024 7981
1024 8543
1024 9624
1024 10705
1024 12388
GetDC failed
157 2354


And again, everything seems to have returned to normal after I closed all instances of the app.

Title: Re: How to avoid leaky Windows programs
Post by: jj2007 on October 24, 2011, 06:37:03 AM
Quote from: MichaelW on October 24, 2011, 05:45:21 AM
So I decided to do an experiment
:U

Quote
Somewhere around the point where GetDC failed, and at ~13K unreleased common DCs, the desktop stopped refreshing correctly. Surprising to me, after I closed all of the running instances everything returned to normal, as near as I can tell by just using the system.

There are 4 aspects that need to be kept apart here:

1. What to do while the app is running: As Michael shows, don't worry, you can have 13,000 dialogs open, in parallel - imagine your taskbar :bg Of course, nobody stops you from creating 1,000 times one and the same font or brush, and deleting it at the end of the WM_PAINT handler; some might call it bad programming practice, though.

2. What to do with a really fat memory allocation (>500 MB) while the app is running: If you don't need them any more, you might release them. However, keeping it should not be a problem, since either your app is active (then others don't need the mem unless they do funny things in background), or another app is active, and if the other one needs the memory, the OS will write your memory to the swap file.

3. What to do with memory, fonts, DCs etc before calling ExitProcess: Nothing, folks, the OS frees everything for you.

4. What to do with memory, fonts, DCs etc before the app is crashing with exception C0000000h: Chase the bug!
Title: Re: How to avoid leaky Windows programs
Post by: jj2007 on October 24, 2011, 10:48:54 PM
Just found one interesting exception on MSDN (http://msdn.microsoft.com/en-us/library/ms633586%28VS.85%29.aspx):

QuoteNo window classes registered by a DLL are unregistered when the DLL is unloaded. A DLL must explicitly unregister its classes when it is unloaded.

I wonder if it applies to other resources, too.
For the freaks, there is a really interesting article here (http://www.denismo.name/b2evolution/index.php/Programming/2009/12/27/debugging-user-object-leak) by Denis Mikhalkin, "Debugging USER object leak"
Title: Re: How to avoid leaky Windows programs
Post by: Tedd on October 25, 2011, 12:31:20 PM
I'm not sure why this is even an issue - if you allocate it, free it when you've finished with it.
It's not a difficult concept, it's not complex to implement, just clean up after yourself ::)
Yes, you may be able to get away with not freeing some things sometimes, on the expectation that it 'should' be freed for you on exit, but you don't know how, when, or even if that will happen. And for the sake of avoiding a few extra function calls, what's the benefit?

How to avoid leaky Windows programs: clean up after yourself!
If you open/create files - close them; if you allocate memory - free it; if you obtain handles to graphical objects - free them; stock objects don't need to be freed by you since they weren't allocated by you.
Title: Re: How to avoid leaky Windows programs
Post by: ixuta on October 25, 2011, 07:16:10 PM
Quote from: hutch-- on October 23, 2011, 09:21:19 PM
...write 16 bit Windows code where one mistake took the OS and every other running app down.

Ah the good old days... :green  reminds me of the day OS/2 first went on sale and I took it down right in front of the rep who was trying to sell it to me! Oh, the shock on his face when OS/2 locked up. :boohoo:

Anyway, this is a good thread, I've looked about for a way to ""Pin this thread to my favorites"", but haven't found a way to do that  ... is there?