Problem with GlobalFree
Olivier Courtois -- Olivier.Courtois@di.epfl.ch Thursday, September 12, 1996 Environment: Windows 95, VC++ 4.0 Few times ago, I developped a MFC app, that should now include a part of code taken out from an older app that I didn't create. In my part, I used new and delete with CObjet and there was no memory leaks, but it turns out to be, that there is now problems with the other part. That code uses GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,...) and GlobalLock() to allocate memory, but it seems that the GlobalFree() function is unable to free it. First I think that the memory was not properly unlocked. So I tested the LockCount (before using GlobalFree) with the GlobalFlags function, and it returns 0 for the lockcount! The GlobalFree simply fails and the return value is (as it should be) equal to the handle of the global memory object. Could that problem be linked with the fact that I used MFC' new and delete in other parts of my programm? How could I solve it? Any idea will be appreciated. Thanks -- OO=====================OO=============================OO===================OO || _/_/_/ _/_/_/ || Olivier.Courtois@di.epfl.ch || || || _/ _/ _/ _/\ || EPFL-DI-LSP || Smile, tomorrow || || _/ _/ _/ _/ _\|| http://diwww.epfl.ch/w3lsp/ || is worse. || || _/_/_/ _/_/_/ _/ || || || OO=====================OO=============================OO===================OO
Mike Blaszczak -- mikeblas@nwlink.com Friday, September 13, 1996 At 05:43 PM 9/12/96 +0200, you wrote: >Environment: Windows 95, VC++ 4.0 >That code uses GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,...) and >GlobalLock() to allocate memory, but it seems that the GlobalFree() >function is unable to free it. What does ::GetLastError() tell you? >First I think that the memory was not properly unlocked. So I >tested the LockCount (before using GlobalFree) with the >GlobalFlags function, and it returns 0 for the lockcount! According to the documentation, that doesn't matter. It says: "Both GlobalFree and LocalFree will free a locked memory object." >Could that problem be linked with the fact that I used MFC' new and >delete in other parts of my programm? How could I solve it? I don't seen any way to connect the two. .B ekiM http://www.nwlink.com/~mikeblas/ These words are my own. I do not speak on behalf of Microsoft.
Eric Kenslow -- webmaster@digilight.com Sunday, September 15, 1996 You may be running into a problem that I had when I first learned Windows programming- are you trying to free the HANDLE returned by GlobalAlloc(), or the POINTER returned by GlobalLock()? GlobalFree() needs the handle, not the pointer. /* Eric Kenslow - Digital Lighthouse Inc. * webmaster@digilight.com * http://www.digilight.com */ ---------- > From: Mike Blaszczak> To: mfc-l@netcom.com > Subject: Re: Problem with GlobalFree > Date: Friday, September 13, 1996 10:27 PM > > At 05:43 PM 9/12/96 +0200, you wrote: > >Environment: Windows 95, VC++ 4.0 > >That code uses GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,...) and > >GlobalLock() to allocate memory, but it seems that the GlobalFree() > >function is unable to free it. > > What does ::GetLastError() tell you? > > >First I think that the memory was not properly unlocked. So I > >tested the LockCount (before using GlobalFree) with the > >GlobalFlags function, and it returns 0 for the lockcount! > > According to the documentation, that doesn't matter. It says: "Both > GlobalFree and LocalFree will free a locked memory object." > > >Could that problem be linked with the fact that I used MFC' new and > >delete in other parts of my programm? How could I solve it? > > I don't seen any way to connect the two. > > .B ekiM > http://www.nwlink.com/~mikeblas/ > These words are my own. I do not speak on behalf of Microsoft. >
T. James Ricketts -- jamesr@gmap.leeds.ac.uk Monday, September 16, 1996 [Mini-digest: 2 responses] Hi Olivier Some months ago we also integrated new MFC-based code (using new/delete) with existing API-based code that used GlobalAlloc/Free. To start with things went disastrously wrong ... 'odd' memory behaviour all over the place. However most problems could be traced down to one (or more) the following: 1) Using 'delete' on 'GlobalAlloc'd pointers (or vice-versa). 2) Forgetting that 'new' doesn't initialise memory in the same way as 'GlobalAlloc(GHND...)' does. 3) Forgetting that 'new' has a much smaller (1-byte ?) granularity of memory-allocation than 'GlobalAlloc' (32-bytes) ! All of which are pretty obvious now but weren't necessarily when the original API code was produced. I'm not sure I ever saw the problem you raised but the above may well be relevant anyway ! James -----From: David.Lowndes@bj.co.uk > In my part, I used new and delete with CObjet and there was no memory leaks, but it turns out to be, that there is now problems with the other part. That code uses GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,...) and GlobalLock() to allocate memory, but it seems that the GlobalFree() function is unable to free it. Could that problem be linked with the fact that I used MFC' new and delete in other parts of my programm? How could I solve it? < Olivier, Your problem is that you're trying to mix different memory managers. You need to modify your code to use the same memory management interface in all components. You can't mix use of an "unknown" implementation of new/delete with GlobalAlloc/Free. One solution might be to override the new/delete operations to have them use GlobalAlloc/Free, but that is inefficient. If you can't change the code using GlobalAlloc/Free, I'd examine your code to see if you can isolate the interface between the areas and agree to use the GlobalAlloc/Free routines just there. Dave Lowndes
Rob Tessier -- Rob_Tessier@iacnet.com Wednesday, September 25, 1996 There's excess confusion here, let's clarify. Mike B. wrote: >GlobalAlloc() is an API function. It doesn't have anything to do with >MFC. GlobalAlloc() works with or without MFC. It doesn't change depending >on which version of MFC you're using. It changes depending on which >version of _Windows(tm) the operating system_ you're using. >>and up allocs memory from the Window's heap. >By definition: see the Win32 or Win16 API references. (Period! >It doesn't matter which 3-rd party memory manager you're using, >or which class library you're using, or even which language you're >using: a call to GlobalAlloc() is a call to the operating system.) true, GlobalAlloc is a call to the WOS but according to the Win32 spec, GlobalAlloc 'supposedly' allocs from your process' default heap, that changed from Win16. From the MSDN, (note the sentences encased by >>>>>>>> <<<<<<<<<) Randy Kath Microsoft Developer Network Technology Group Created: April 3, 1993 Two Types of Heaps in Win32 Every process in Windows NT has one heap called the default heap. Processes can also have as many other dynamic heaps as they wish, simply by creating and destroying them on the fly. >>>>>>>The Win32 subsystem uses the default heap for all global and local memory management functions, and the C run-time library uses the default heap for supporting malloc functions.<<<<<<<<< The heap memory functions, which indicate a specific heap by its handle, use dynamic heaps. The behavior of dynamic heaps is discussed in the "Win32 Heap Memory API" section later in this article. The default and dynamic heaps are basically the same thing, but the default heap has the special characteristic of being identifiable as the default. This is how the C run-time library and the Win32 subsystem identify which heap to allocate from. The GetProcessHeap function returns a handle to the default heap for a process. >>>>>>>>>>Since functions such as GlobalAlloc or malloc are executed within the context of the thread that called them, they can simply call GetProcessHeap to retrieve a handle to the default heap, and then manage memory accordingly<<<<<<<<<<. Global and Local Memory Functions At first glance it appears that the local and global memory management functions exist in Win32 purely for backward compatibility with Windows version 3.1. This may be true, but the functions are managed as efficiently as the new heap functions discussed below. In fact, porting an application to Win32 from Windows 3.1 does not necessarily include migrating from global and local memory functions to heap memory functions. The global and local functions offer the same basic capabilities (and then some) and are just as fast to work with. If anything, they are probably more convenient to work with because you do not have to keep track of a heap handle. Nonetheless, the implementation of these functions is not the same as it was for Windows 3.1. Windows 3.1 had a global heap, and each application had a local heap. Those two heap managers implemented the global and local functions. Allocating memory via GlobalAlloc meant retrieving a chunk of memory from the global heap, while LocalAlloc allocated memory from the local heap. >>>>>>>>>>>>Win32 has a single heap for both types of functionsthe default heap described above.<<<<<<<<<<<< Also in Windows 3.1 the local memory functions worked with _near pointers and the global functions worked with _far pointers. In Win32 they both work with 32-bit pointers in the process's address space. Actually, it appears GlobalAlloc allocs memory from the Window's heap and not from my process' heap despite what the article states. Isn't this true???? See my sample program below. >>alloced via new, malloc, and embedded objects are alloc'd from your >>application's process heap. >That, on the other hand, really depends on which compiler and >runtime library you're using. And it depends on which _version_ of >those tools you're using, too. CRT Library Managing memory in Windows prior to Win32 involved a great deal of uncertainty about using the C run-time (CRT) library. With Win32 there should be little hesitation. >>>>>>>>>>>>The CRT library in Win32 is implemented in a manner similar to FIXED memory allocated via the local and global memory management functions. The CRT library is also implemented using the same default heap manager as the global and local memory management functions.<<<<<<<<<<<<<<< >>>>>>>>>>>Subsequent memory allocations via malloc, GlobalAlloc, and LocalAlloc return pointers to memory allocated from the same heap.<<<<<<<<<<< The heap manager does not divide its space among the CRT and global/local memory functions, and it does not maintain separate heaps for these functions. Instead, it treats them the same, promoting consistent behavior across the types of functions. As a result, you can now write code using the functions you're most comfortable with. And, if you're interested in portability, you can safely use the CRT functions exclusively for managing heap memory. >>GloabalAlloc in MFC 4.1 and up allocs memory from the Window's heap. memory >>alloced via new, malloc, and embedded objects are alloc'd from your >>application's process heap. My reference to a specific version of MFC regarding GlobalAlloc was incorrect. Thanks for pointing that out. What I meant to suggest was that the CRT shipping with MSVC apparently changed it's behavior from release to release. David K's "Inside VC++ Version 4" stated on pg 203 that the CRT heap was not the same as the process' heap. When I wrote him, he told me the CRT guys told him that they changed it from what's stated in the article, to using it's own heap, and now back full circle to using the default process heap. This has happened in VC4.1 CRT. That's what I meant regarding version specific. To verify, I tried this little example under VC4.1 Windows 95: // //rpt: Experiment with where mem is alloc'ed from when using GlobalAlloc, // LocalAlloc, malloc, new. // char *pMem, *pMem2, *pMem3; CMemoryState oldMemState, newMemState, diffMemState; oldMemState.Checkpoint(); char msg[40]; //doesn't alloc from our heap //char msg2[] = "hello"; //"hello" still not alloced from our heap CString s = "hello"; //"hello" IS alloced from our heap //this alloc won't happen from our heap, but from Windows!! pMem = (char*) GlobalAlloc(GMEM_FIXED, 123); //this alloc is from our heap pMem2 = new char[55]; //this alloc is from our heap pMem3 = (char*) malloc(77); oldMemState.DumpAllObjectsSince(); newMemState.Checkpoint(); if ( diffMemState.Difference( oldMemState, newMemState ) ) { TRACE( "Memory leaked!\n" ); diffMemState.DumpStatistics(); } Dumping objects -> {82} normal block at 0x00661B0C, 77 bytes long. Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD C:\exp\RobsGUI\MainFrm.cpp(95) : {81} normal block at 0x00661AAC, 55 bytes long. Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD strcore.cpp(76) : {80} normal block at 0x00661A70, 18 bytes long. Data: < hell> 01 00 00 00 05 00 00 00 05 00 00 00 68 65 6C 6C Object dump complete. Memory leaked! 0 bytes in 0 Free Blocks. 150 bytes in 3 Normal Blocks. 0 bytes in 0 CRT Blocks. 0 bytes in 0 Ignore Blocks. 0 bytes in 0 Client Blocks. Largest number used: 146 bytes. Total allocations: 150 bytes. To conclude: GlobalAlloc does not alloc from process heap (contrary to MSDN article above), new, malloc allocs from process heap (atleast in CRT of MSVC4.1). I once wrote: >>Since your process's heap is optimized more for new/malloc >>where smaller allocs are performed, you can save larger allocs >>for GlobalAlloc or create your own heap via HeapCreate. >>Best not to mix large and small allocs into the same heap >>as you end up with fragmentation like your disk drive. >All I can say to this is: no, you're wrong. Could you elaborate. I'd appreciate your opinion. -Rob -----From: Mike BlaszczakThis part of the note was not attributed to a particular author. That's good, since I'm normaly considered "a prick" for telling people when their answers are actualy wrong: I obviously can't complain about anyone in particular here! >>It is not a good style to use GlobalAlloc in an MFC program. That's absolutely wrong. Period! You can call GlobalAlloc() whenver you want to. It's downright necessary, in some circumstances. My response to you isn't a matter of "style": it's a matter of _fact_. >Since MSVC 2.0 we finally reached the desirable situation >to be able to use new/delete overall. I'm not sure I'd agree with that. Look: new (malloc/calloc) and delete (free) are general-purpose routines. They might break badly, or at a minimum, provide less performance than you want, in some certain situations. That's something you'll need to decide for yourself, based on the situation you're in. >>Using malloc and new together in a program cann cause >>unpredictable results (see Scott Meyers, >>"Effective C++ programming"). There's three possible truths here: a) Scott Meyers is dead-down wrong b) Actually, Scott Meant that: char* pstr = new char[1024]; free(pstr); is a bad idea. That is, mixing C allocators and C++ releasers (or vise-versa) is bad, but only over _the same allocation_. c) You're quoting Scott Meyers incorrectly. My money parlayed between b) and c). (And, as t turns out, I'm the Jimmy The Greek of C++ programming.) >>So, just recode the thing! If you clap your hands and really beleive, you can fly! But, back on Earth: a) you might not have time to "recode the thing" b) you might not _need_ to "recode the thing" .B ekiM http://www.nwlink.com/~mikeblas/ Don't look at my hands: look at my _shoulders_! These words are my own. I do not speak on behalf of Microsoft.
Alexander Grigoriev -- alegr@aha.ru Monday, September 30, 1996 Rob, There is no such thing as Win32 global heap. Both GlobalAlloc and LocalAlloc get the memory from the default process heap. You can safely call LocalFree for a pointer obtained through GlobalAlloc. You also confused CRT debug memory manager with Win32 heap manager. Memor= y allocated directly from the Windows heap cannot be checked by the CRT for leaks. CRT mem manager adds extra bytes for each allocation, where it stores additional information, such as object type, file and line number where the object has been allocated, and so on. Althogh CRT call Windows heap manager, pointer returned to the applicatio= n may differ from one returned by HeapAlloc. MSVC CRT prior to 4.2 used Windows heap for all the application requests, but the allocated blocks might have extra bytes for CRT purposes. In MSVC 4.2, small requests are handled in a special way. Regards Alex ---------- > From: Rob Tessier> To: mfc-l > Cc: Mike Blaszczak > Subject: Re: Problem with GlobalFree > Date: 25 =D3=C5=CE=D4=D1=C2=D2=D1 1996 =C7. 17:09 >=20 > There's excess confusion here, let's clarify. >=20 > Mike B. wrote: >=20 > >GlobalAlloc() is an API function. It doesn't have anything to do with > >MFC. GlobalAlloc() works with or without MFC. It doesn't change depending > >on which version of MFC you're using. It changes depending on which > >version of _Windows(tm) the operating system_ you're using. >=20 > >>and up allocs memory from the Window's heap.=20 >=20 > >By definition: see the Win32 or Win16 API references. (Period! > >It doesn't matter which 3-rd party memory manager you're using,=20 > >or which class library you're using, or even which language you're > >using: a call to GlobalAlloc() is a call to the operating system.) >=20 > true, GlobalAlloc is a call to the WOS but according to the Win32 spec, > GlobalAlloc 'supposedly' allocs from your process' default heap, that > changed from Win16. From the MSDN, (note the sentences encased > by >>>>>>>> <<<<<<<<<) >=20 > Randy Kath > Microsoft Developer Network Technology Group > Created: April 3, 1993 > Two Types of Heaps in Win32 [stuff deleted] >=20 > Actually, it appears GlobalAlloc allocs memory from the Window's heap a= nd not > from my process' heap despite what the article states. Isn't this true???? =20 > See my > sample program below. >=20 > >>alloced via new, malloc, and embedded objects are alloc'd from your=20 > >>application's process heap.=20 >=20 > >That, on the other hand, really depends on which compiler and > >runtime library you're using. And it depends on which _version_ of > >those tools you're using, too. >=20 > CRT Library > Managing memory in Windows prior to Win32 involved a great deal of uncertainty=20 > about using the C run-time (CRT) library. With Win32 there should be little=20 > hesitation. >>>>>>>>>>>>The CRT library in Win32 is implemented in a manner=20 > similar to FIXED memory allocated via the local and global memory management=20 > functions. The CRT library is also implemented using the same default heap=20 > manager as the global and local memory management functions.<<<<<<<<<<<<<<< > >>>>>>>>>>>Subsequent memory allocations via malloc, GlobalAlloc, and LocalAlloc > return pointers to memory allocated from the same heap.<<<<<<<<<<< The heap=20 > manager does not divide its space among the CRT and global/local memory= =20 > functions, and it does not maintain separate heaps for these functions.= =20 > Instead, it treats them the same, promoting consistent behavior across the=20 > types of functions. As a result, you can now write code using the functions=20 > you're most comfortable with. And, if you're interested in portability, you can=20 > safely use the CRT functions exclusively for managing heap memory. >=20 > >>GloabalAlloc in MFC 4.1 and up allocs memory from the Window's heap.=20 memory=20 > >>alloced via new, malloc, and embedded objects are alloc'd from your=20 > >>application's process heap.=20 >=20 > My reference to a specific version of MFC regarding GlobalAlloc was incorrect. > Thanks for pointing that out. What I meant to suggest was that the CRT > shipping with MSVC apparently changed it's behavior from release to release. >=20 > David K's "Inside VC++ Version 4" stated on pg 203 that the CRT heap wa= s not > the same as the process' heap. When I wrote him, he told me the CRT gu= ys > told him that they changed it from what's stated in the article, to usi= ng it's=20 > own heap,=20 > and now back full circle to using the default process heap. This has happened > in VC4.1 CRT. That's what I meant regarding version specific. >=20 > To verify, I tried this little example under VC4.1 Windows 95: >=20 > // > //rpt: Experiment with where mem is alloc'ed from when using GlobalAllo= c, > // LocalAlloc, malloc, new. > // > char *pMem, *pMem2, *pMem3; >=20 > CMemoryState oldMemState, newMemState, diffMemState; > oldMemState.Checkpoint(); >=20 > char msg[40]; //doesn't alloc from our heap > //char msg2[] =3D "hello"; //"hello" still not alloced from our heap > CString s =3D "hello"; //"hello" IS alloced from our heap=20 >=20 > //this alloc won't happen from our heap, but from Windows!! > pMem =3D (char*) GlobalAlloc(GMEM_FIXED, 123); > //this alloc is from our heap > pMem2 =3D new char[55]; > //this alloc is from our heap > pMem3 =3D (char*) malloc(77);=20 >=20 > oldMemState.DumpAllObjectsSince(); >=20 > newMemState.Checkpoint(); > if ( diffMemState.Difference( oldMemState, newMemState ) ) > { > TRACE( "Memory leaked!\n" ); > diffMemState.DumpStatistics(); > } >=20 > Dumping objects -> > {82} normal block at 0x00661B0C, 77 bytes long. > Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD = CD > C:\exp\RobsGUI\MainFrm.cpp(95) : {81} normal block at 0x00661AAC, 55 bytes long. > Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD = CD > strcore.cpp(76) : {80} normal block at 0x00661A70, 18 bytes long. > Data: < hell> 01 00 00 00 05 00 00 00 05 00 00 00 68 65 6C = 6C > Object dump complete. > Memory leaked! > 0 bytes in 0 Free Blocks. > 150 bytes in 3 Normal Blocks. > 0 bytes in 0 CRT Blocks. > 0 bytes in 0 Ignore Blocks. > 0 bytes in 0 Client Blocks. > Largest number used: 146 bytes. > Total allocations: 150 bytes. >=20 > To conclude: GlobalAlloc does not alloc from process heap (contrary to MSDN=20 > article above), > new, malloc allocs from process heap (atleast in CRT of MSVC4.1). >=20 > I once wrote: > >>Since your process's heap is optimized more for new/malloc > >>where smaller allocs are performed, you can save larger allocs > >>for GlobalAlloc or create your own heap via HeapCreate.=20 > >>Best not to mix large and small allocs into the same heap=20 > >>as you end up with fragmentation like your disk drive. >=20 > >All I can say to this is: no, you're wrong. >=20 > Could you elaborate. I'd appreciate your opinion. >=20 > -Rob >=20
| Вернуться в корень Архива |