15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


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 Blaszczak 

This 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





| Вернуться в корень Архива |