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

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


new, delete

Albert Szilvasy -- szilvasy@almos.vein.hu
Wednesday, April 03, 1996

Hi,

NT 3.51 VC 4.0

I'm building a dll that uses MFC in a dll and encountered a strange 
behaviour.

I tried to use new and delete for a non-CObject derived class. The 
new performs fine in that it does debug memory allocation. However, 
when I  try to call delete the exe I'm writing the dll to asserts 
saying that something wrong on the heap.
So long, I thought. (I don't have access to the source code of the
exe)
BUT when I do the same thing with a CObject derived class everything 
is FINE. The new call ends up in the same global debug new operator 
(CObject::new calls it) and delete frees the memory without any 
scorning on side of the exe. (I can't step into the delete in either 
of the cases)
Any idea what's happening? What's the difference?
Thanks in advance,
Cheers,
Albert
--
UofV,Hungary



daveferg@niagara.com
Friday, April 05, 1996

NT 3.51 VC 4.1

I have a similar problem using a 3'rd party class library maintained
in dll. However if I derive a class from this dll in my application
the problem goes away. Clearly there is some difference in the new in 
the app vs the dll. The problem also goes away if I am not using the 
debug version of new. For now it isn't hard for me to work around this
quirk but I would be interested in any further discussion on the subject.

Dave
>Hi,
>
>NT 3.51 VC 4.0
>
>I'm building a dll that uses MFC in a dll and encountered a strange 
>behaviour.
>
>I tried to use new and delete for a non-CObject derived class. The 
>new performs fine in that it does debug memory allocation. However, 
>when I  try to call delete the exe I'm writing the dll to asserts 
>saying that something wrong on the heap.
>So long, I thought. (I don't have access to the source code of the
>exe)
>BUT when I do the same thing with a CObject derived class everything 
>is FINE. The new call ends up in the same global debug new operator 
>(CObject::new calls it) and delete frees the memory without any 
>scorning on side of the exe. (I can't step into the delete in either 
>of the cases)
>Any idea what's happening? What's the difference?
>Thanks in advance,
>Cheers,
>Albert
>--
>UofV,Hungary
>
>




David W. Gillett -- DGILLETT@expertedge.com
Friday, April 05, 1996

[Mini-digest: 2 responses]

> NT 3.51 VC 4.0
> 
> I'm building a dll that uses MFC in a dll and encountered a strange 
> behaviour.
> 
> I tried to use new and delete for a non-CObject derived class. The 
> new performs fine in that it does debug memory allocation. However, 
> when I  try to call delete the exe I'm writing the dll to asserts 
> saying that something wrong on the heap.
> So long, I thought. (I don't have access to the source code of the
> exe)
> BUT when I do the same thing with a CObject derived class everything 
> is FINE. The new call ends up in the same global debug new operator 
> (CObject::new calls it) and delete frees the memory without any 
> scorning on side of the exe. (I can't step into the delete in either 
> of the cases)
> Any idea what's happening? What's the difference?

  There was a thread here within the last week about this, which 
turned upon the fact that a Win32 process can have multiple heaps -- 
and that each module (.EXE, .DLL) gets its own defualt heap.  
Presumably the standard new and delete work on the current module's 
default heap.

  The fact that it worked with CObject points to three possible fixes:

(1) Override new and delete in your own class.  They don't need to do 
anything fancy, but this should make sure that they both refer to 
the heap of the module where your class is defined.  (I believe that 
this is how CObject is avoiding the problem.)

(2) Export routines to create and destroy instances of your class, so 
that new and delete actually get called from within the same module.  
This is less satisfactory, since it requires exceptional syntax to 
use your class, especially if you want to support arrays of your 
objects.

(3) Derive your objects from CObject.  There's probably all sorts of 
stuff CObject offers that you don't care about, but the overhead is 
probably not much more than a single vtable for your class and a 
vtable pointer in every instance, and in a multi-module application, 
that's not likely to be noticeable.  You may discover next week that 
you have some use, after all, for other aspects of CObject, and 
they'll come virtually free.

Dave


 
-----From: Dan Kirby 

Hi,
Articles Q121216 and Q122675 in the Microsoft knowledgebase may gives some 
clues.  It appears that there needs to be more information in your message, 
perhaps some snippets of code of where you are creating and deleting the 
non-Cobject objects. Are the objects being allocated and deleted in the DLL 
and if so, where?  Is this a regular DLL or extension DLL?

--dan



djw@arbortext.com
Saturday, April 06, 1996

>  There was a thread here within the last week about this, which 
>turned upon the fact that a Win32 process can have multiple heaps -- 
>and that each module (.EXE, .DLL) gets its own defualt heap.  
>Presumably the standard new and delete work on the current module's 
>default heap.

This doesn't seem right.  New and delete are using the C runtime malloc and
free.  As of VC++ 4.0, even the extra heap debugging aids that used to be in MFC
have been moved down into the CRT.  Unless multiple copies of the CRT are
being loaded, by statically linking the C runtime into a dll for example, there
shouldn't be an issue of multiple heaps.

Perhaps Mike B. could give us a definitive lecture on this topic.

Dave Wilson  djw@arbortext.com
ArborText Inc.  Ann Arbor Michigan



Dean McCrory -- deanm@microsoft.com
Sunday, April 07, 1996

There is no "default" heap for a "module" in Win32, but Win32 does in
fact have the capability to deal with multiple, independent heaps (see
HeapCreate, etc. APIs).  For each separate C-runtime that you link in,
you will get code which uses a separate heap for that CRT.  If you
dyanamically link to the CRT (msvcrt40.dll) then you have code which is
sharing a heap, and so you can freely mix new/delete from separate
modules.

General rule to keep in mind: if two modules A and B are calling into
the *same* new and delete, then everything is fine.  If they are calling
into separate new and delete implementations, then you are probably
doing something bad.  The only way to share new and delete
implementations is by dynamically linking to a single DLL which
implements them.

// Dean McCrory
// Team Jakarta

>----------
>From: 	djw@arbortext.com[SMTP:djw@arbortext.com]
>Sent: 	Saturday, April 06, 1996 11:57 AM
>To: 	mfc-l@netcom.com
>Cc: 	Albert Szilvasy; djw@arbortext.com
>Subject: 	Re: new, delete  
>
>>  There was a thread here within the last week about this, which 
>>turned upon the fact that a Win32 process can have multiple heaps -- 
>>and that each module (.EXE, .DLL) gets its own defualt heap.  
>>Presumably the standard new and delete work on the current module's 
>>default heap.
>
>This doesn't seem right.  New and delete are using the C runtime malloc
>and
>free.  As of VC++ 4.0, even the extra heap debugging aids that used to
>be in MFC
>have been moved down into the CRT.  Unless multiple copies of the CRT
>are
>being loaded, by statically linking the C runtime into a dll for
>example, there
>shouldn't be an issue of multiple heaps.
>
>Perhaps Mike B. could give us a definitive lecture on this topic.
>
>Dave Wilson  djw@arbortext.com
>ArborText Inc.  Ann Arbor Michigan
>



Mario Contestabile -- Mario_Contestabile.UOS__MTL@UOSMTL2.universal.com
Monday, April 08, 1996

[Mini-digest: 2 responses]

>>  There was a thread here within the last week about this, which 
>>turned upon the fact that a Win32 process can have multiple heaps -- 
>>and that each module (.EXE, .DLL) gets its own defualt heap.  
>>Presumably the standard new and delete work on the current module's 
>>default heap.

>This doesn't seem right.  New and delete are using the C runtime malloc and
>free.  As of VC++ 4.0, even the extra heap debugging aids that used to be in 
MFC
>have been moved down into the CRT.

I thought that as of 4.0 new and delete used GlobalAlloc() and GlobalFree().

mcontest@universal.com

-----From: "Albert Szilvasy" 

Thanks for all of you who replied. Finally, overloading the new and 
delete operators in non-CObject derived classes as suggested by
David W. Gillett  and the KB article Q122675 
solved the problem. Code sniplet follows:

#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
void* PASCAL operator new(size_t nSize, LPCSTR lpszFileName, int nLine) 
{
 return ::operator new(nSize, _CLIENT_BLOCK, lpszFileName, nLine);
}
void  operator delete( void* p ) 
{
 _free_dbg(p, _CLIENT_BLOCK);
}
#endif

Thanks again,
Albert
--
UofV,Hungary



djw@arbortext.com
Wednesday, April 10, 1996

>>>  There was a thread here within the last week about this, which 
>>>turned upon the fact that a Win32 process can have multiple heaps -- 
>>>and that each module (.EXE, .DLL) gets its own defualt heap.  
>>>Presumably the standard new and delete work on the current module's 
>>>default heap.
>
>>This doesn't seem right.  New and delete are using the C runtime malloc and
>>free.  As of VC++ 4.0, even the extra heap debugging aids that used to be in 
MFC
>>have been moved down into the CRT.
>...
>I thought that as of 4.0 new and delete used GlobalAlloc() and GlobalFree().

If I properly understood the section on memory in the new edition of
Kruglinsky's book (which I like a *lot*), new and delete (if not overridden,
of course) use the CRT, which in turn uses VirtualAlloc to obtain large blocks
of memory.  A call to new only results in a call into the operating system
when the CRT needs to add another large block.  I recall him saying that the
first request will be for one meg; the second for two meg; the third for four;
and so on.  Also, he said that as of 4.0 the free list data structure has been
moved outside of the heap, and is very compact.  Therefore traversals of the
free list no longer result in touching large numbers of virtual pages, thus
avoiding a great deal of slow paging (as is the case in "normal" heap
implementations).  This should reduce the need for extra memory management
products.

You would want to use GlobalAlloc yourself when allocating space that has to
be passed to an api entry point that requires a handle to movable memory.
Also, if you need a large block there might be an advantage to using GlobalAlloc
to avoid fragmenting the heap the CRT is maintaining.  Kruglinsky discusses
when this would be appropriate.  He, in turn, suggests reading Richter's books
for deeper information about some things, such as sharing memory and memory
mapped files.

Dave Wilson  djw@arbortext.com
ArborText Inc.  Ann Arbor Michigan



Mike Blaszczak -- mikeblas@msn.com
Saturday, April 13, 1996

[Mini-digest: 3 responses]

>I thought that as of 4.0 new and delete used GlobalAlloc() and GlobalFree().

They do, essentially: there's not a very big difference between 
HeapAlloc()/HeapFree() and GlobalAlloc()/GlobalFree().  It is just that the 
Heap-routines work on a private heap while the Global()-routines work on the 
Windows core heap.

> If I properly understood the section on memory in the new edition of
> Kruglinsky's book (which I like a *lot*),

It's spelled "Kruglinski".  I'm afraid that either you're misrecalling these 
facts or David got them wrong in the book to begin with. The CRTL memory 
management routines are probably the most often updated part of the product: 
they changed substantially in VC++ 4.0, and will change substantially again.  
This is a dangerous thing to try and document.

> new and delete (if not overridden,
> of course) use the CRT, which in turn uses VirtualAlloc to obtain large 
blocks
> of memory. 

The VC++ 4.0 and 4.1 C Runtimes don't ever call VirtualAlloc() during the 
handling of memory allocations.  They _do_ use a VirtualAlloc() to get a block 
of memory in the DLL builds for per-process state information, but other than 
that, they don't use VirtualAlloc().

By using "find in files" or grep through the CRT\SRC directory on your CD, you 
(or David Kruglinski) could verify this for yourself.  (You _will_ get hits on 
VirtualAlloc(), but they're #ifdef'ed out.)  You could also write a four-line 
application and step into the memory allocation routines with the debugger.

Instead, they directly call HeapAlloc() in response to every request for 
memory you make via operator new() or malloc() or any of their friends.   In a 
debug build, you'll see lots more work going on to set up arenas for the 
actually allocated data, but everything ends up going to HeapAlloc() and not 
VirtualAlloc().

> A call to new only results in a call into the operating system
> when the CRT needs to add another large block.  I recall him saying that the
> first request will be for one meg; the second for two meg; the third for 
four;
> and so on. 

This is obsolete information.  It seems to describe the pre-4.0 C Runtime 
libraries.

> Also, he said that as of 4.0 the free list data structure has been
> moved outside of the heap, and is very compact.  Therefore traversals of the
> free list no longer result in touching large numbers of virtual pages, thus
> avoiding a great deal of slow paging (as is the case in "normal" heap
> implementations). 

Since 4.0 doesn't manage a list of free data by itself, this is incorrect. 
Windows its own self is actually managing the memory, so there is no free 
memory list managed by the CRTL.  In ver>=4.0, The free pool is something that 
Windows manages, not the CRTL.

> This should reduce the need for extra memory management
> products.

I really can't comment on that one.

> You would want to use GlobalAlloc yourself when allocating space that has to
> be passed to an api entry point that requires a handle to movable memory.

In Win32, is any memory moveable?

> Also, if you need a large block there might be an advantage to using 
GlobalAlloc
> to avoid fragmenting the heap the CRT is maintaining. 

GlobalAlloc() doesn't affect the CRT heap in VC++ 4.0.

It sounds like your recollection and/or the Kruglinski book really document 
what's going on in VC++ 2.x, not VC++ 4.0 or 4.1.

.B ekiM
TCHAR szSpringtime[] = _T("Check twice and save a life: motorcycles are 
everywhere!");
-----From: grossman@teleport.com (Jeff Grossman)

To the best of my knowledge, what Dave Wilson says here is completely
accurate. However, there is more. If you have statically linked the CRT
with each DLL, each "copy" of the CRT will maintain its own local memory
pool and free list. Hence, if you allocate an object in one DLL and then
try to free it by giving that pointer to the CRT being used in another
DLL, that second CRT will, in effect, say "I never knew you" and generate
the run-time error: Invalid pointer passed to RtlFreeHeap.

I've run into this problem with an ODBC driver vendor, and also had the
problem myself in a multiple-DLL project with a slip-of-the-finger in
the release build options. Note that this problem also will occur if you
accidently mix release and debug CRTs, even if both are in DLL form.

My standard policy is always to use the multi-threaded DLL CRT (release or
debug version) and not worry about the problem.

Jeff

-----From: Niels Ull Jacobsen 

I guess we're straying a bit off MFC here?
Kruglinski may say so. The CRT source says otherwise :-).

According to the CRT makefile provided with MSVC 4.0, except for the 68K and
PowerMac versions of the runtime library, all versions are build using WINHEAP
where malloc/free and new/delete maps more or less directly to the
HeapAlloc, HeapFree etc calls of Win32.

[...]
>Dave Wilson  djw@arbortext.com
Niels Ull Jacobsen, Krьger A/S (nuj@kruger.dk)
Everything stated herein is THE OFFICIAL POLICY of the entire Kruger group
and should be taken as legally binding in every respect. Pigs will grow
wings and fly.




eric jung -- ejung@dbintellect.com
Tuesday, April 16, 1996


Mike B.,

Two questions:
First, I would greatly appreciate it if you could point me to a couple of 
sources (books or whatever) which would explain this to me in greater 
detail...

Second:
>They do, essentially: there's not a very big difference between
>HeapAlloc()/HeapFree() and GlobalAlloc()/GlobalFree().  It is just that the 

>Heap-routines work on a private heap while the Global()-routines work on 
the
>Windows core heap.
Assuming that the entire private heap is always returned to the global free 
list when the app terminates, and assuming that allocations from the global 
core heap are not returned to the global free list unless explicity deleted, 
wouldn't it be better if 4.0's new and delete operators used 
HeapAlloc()/HeapFree()?

Please tell me if my assumptions are incorrect (which they probably are), or 
if they are correct perhaps you know MS's rationale for this implementation 
of new/delete?

Thanks,
Eric Jung
ejung@dbintellect.com
 ----------
From: owner-mfc-l
To: mfc-l
Subject: RE: new, delete
Date: Saturday, April 13, 1996 7:56AM

[Mini-digest: 3 responses]

>I thought that as of 4.0 new and delete used GlobalAlloc() and 
GlobalFree().

They do, essentially: there's not a very big difference between
HeapAlloc()/HeapFree() and GlobalAlloc()/GlobalFree().  It is just that the
Heap-routines work on a private heap while the Global()-routines work on the 

Windows core heap.

> If I properly understood the section on memory in the new edition of
> Kruglinsky's book (which I like a *lot*),

It's spelled "Kruglinski".  I'm afraid that either you're misrecalling these 

facts or David got them wrong in the book to begin with. The CRTL memory
management routines are probably the most often updated part of the product: 

they changed substantially in VC++ 4.0, and will change substantially again. 

This is a dangerous thing to try and document.

> new and delete (if not overridden,
> of course) use the CRT, which in turn uses VirtualAlloc to obtain large
blocks
> of memory.

The VC++ 4.0 and 4.1 C Runtimes don't ever call VirtualAlloc() during the
handling of memory allocations.  They _do_ use a VirtualAlloc() to get a
block
of memory in the DLL builds for per-process state information, but other 
than
that, they don't use VirtualAlloc().

By using "find in files" or grep through the CRT\SRC directory on your CD,
you
(or David Kruglinski) could verify this for yourself.  (You _will_ get hits
on
VirtualAlloc(), but they're #ifdef'ed out.)  You could also write a 
four-line
application and step into the memory allocation routines with the debugger.

Instead, they directly call HeapAlloc() in response to every request for
memory you make via operator new() or malloc() or any of their friends.   In
a
debug build, you'll see lots more work going on to set up arenas for the
actually allocated data, but everything ends up going to HeapAlloc() and not 

VirtualAlloc().

> A call to new only results in a call into the operating system
> when the CRT needs to add another large block.  I recall him saying that 
the
> first request will be for one meg; the second for two meg; the third for
four;
> and so on.

This is obsolete information.  It seems to describe the pre-4.0 C Runtime
libraries.

> Also, he said that as of 4.0 the free list data structure has been
> moved outside of the heap, and is very compact.  Therefore traversals of 
the
> free list no longer result in touching large numbers of virtual pages, 
thus
> avoiding a great deal of slow paging (as is the case in "normal" heap
> implementations).

Since 4.0 doesn't manage a list of free data by itself, this is incorrect.
Windows its own self is actually managing the memory, so there is no free
memory list managed by the CRTL.  In ver>=4.0, The free pool is something
that
Windows manages, not the CRTL.

> This should reduce the need for extra memory management
> products.

I really can't comment on that one.

> You would want to use GlobalAlloc yourself when allocating space that has 
to
> be passed to an api entry point that requires a handle to movable memory.

In Win32, is any memory moveable?

> Also, if you need a large block there might be an advantage to using
GlobalAlloc
> to avoid fragmenting the heap the CRT is maintaining.

GlobalAlloc() doesn't affect the CRT heap in VC++ 4.0.

It sounds like your recollection and/or the Kruglinski book really document
what's going on in VC++ 2.x, not VC++ 4.0 or 4.1.

.B ekiM
TCHAR szSpringtime[] = _T("Check twice and save a life: motorcycles are
everywhere!");
 -----From: grossman@teleport.com (Jeff Grossman)

To the best of my knowledge, what Dave Wilson says here is completely
accurate. However, there is more. If you have statically linked the CRT
with each DLL, each "copy" of the CRT will maintain its own local memory
pool and free list. Hence, if you allocate an object in one DLL and then
try to free it by giving that pointer to the CRT being used in another
DLL, that second CRT will, in effect, say "I never knew you" and generate
the run-time error: Invalid pointer passed to RtlFreeHeap.

I've run into this problem with an ODBC driver vendor, and also had the
problem myself in a multiple-DLL project with a slip-of-the-finger in
the release build options. Note that this problem also will occur if you
accidently mix release and debug CRTs, even if both are in DLL form.

My standard policy is always to use the multi-threaded DLL CRT (release or
debug version) and not worry about the problem.

Jeff

 -----From: Niels Ull Jacobsen 

I guess we're straying a bit off MFC here?
Kruglinski may say so. The CRT source says otherwise :-).

According to the CRT makefile provided with MSVC 4.0, except for the 68K and
PowerMac versions of the runtime library, all versions are build using 
WINHEAP
where malloc/free and new/delete maps more or less directly to the
HeapAlloc, HeapFree etc calls of Win32.

[...]
>Dave Wilson  djw@arbortext.com
Niels Ull Jacobsen, Kr?ger A/S (nuj@kruger.dk)
Everything stated herein is THE OFFICIAL POLICY of the entire Kruger group
and should be taken as legally binding in every respect. Pigs will grow
wings and fly.




djw@arbortext.com
Wednesday, April 17, 1996

>> If I properly understood the section on memory in the new edition of
>> Kruglinsky's book (which I like a *lot*),
>
>It's spelled "Kruglinski".  I'm afraid that either you're misrecalling these 
>facts or David got them wrong in the book to begin with. The CRTL memory 
>management routines are probably the most often updated part of the product: 
>they changed substantially in VC++ 4.0, and will change substantially again.  
>This is a dangerous thing to try and document.

With the exception of the last letter of Mr. Kruglinski's name, a review of
pages 203-204 of the book indicate that my recollections were reasonably
accurate.  (The full reference, for anyone who wants to check out the book,
is "Inside Visual C++ The Standard Reference for Programming with Microsoft
Visual C++ Version 4", by David J. Kruglinski, copyright 1996, Microsoft
Press. $45.00 US.)  The cover says "Covers: MFC 4.0 ...".

>By using "find in files" or grep through the CRT\SRC directory on your CD, you 
>(or David Kruglinski) could verify this for yourself.  (You _will_ get hits on 
>VirtualAlloc(), but they're #ifdef'ed out.)  You could also write a four-line 
>application and step into the memory allocation routines with the debugger.

Guilty.  I took what I read at face value, and I'm more than old enough to know
better.  You may trust that I've now been thoroughly disabused of the notion
that just because I'd recently read something relevant to a question on this
mailing list, that I could make a sensible contribution.

>This is obsolete information.  It seems to describe the pre-4.0 C Runtime 
>libraries.

I'm still favorably impressed by the book, so I'll be charitable and assume
that the author overlooked a section while making revisions for the 3rd
edition.  Another possibility would be that, given the time lag in getting a
book printed, he was working with something different than 4.0 as it was
finally released.

>> You would want to use GlobalAlloc yourself when allocating space that has to
>> be passed to an api entry point that requires a handle to movable memory.
>
>In Win32, is any memory moveable?

Since Mike would presumably know the answer to that, I have to guess that was
a rhetorical question.  But anyway, what Mr. Kruglinski says is, roughly,
that while moveable memory is an artifact of Win16, it continues to exist to
support GlobalReAlloc.  Also, he says many library functions use HGLOBAL
return values and parameters.  "If you're required to supply an HGLOBAL
parameter, to be absolutely safe you should generate it with a GlobalAlloc(
GMEM_MOVEABLE...) call just in case the called function decides to call
GlobalRealloc and expects the handle value to be unchanged."  Also, he says
"...but the HGLOBAL values returned by OLE are moveable, so you have to call
GlobalLock."

I suppose it wouldn't be appropriate for Mike to review Mr. Kruglinski's book
(even if he had the time and inclination), being an author himself.  Perhaps
someone else better qualified than I seem to be could post a review?

Dave Wilson  djw@arbortext.com




Mike Blaszczak -- mikeblas@msn.com
Saturday, April 20, 1996

From: 	owner-mfc-l@netcom.com on behalf of David J. Wilson
Sent: 	Wednesday, April 17, 1996 7:10 AM

>>It's spelled "Kruglinski".  I'm afraid that either you're misrecalling these
>>facts or David got them wrong in the book to begin with.

> a review of pages 203-204 of the book indicate that my recollections
> were reasonably accurate. 

So, it's unfortunately the latter case.  Like I said in my original note, the 
memory manager in the runtime libraries has been very turbulent lately... so 
it's possible that Mr Kruglinski just didn't update the text.  I forwarded 
your note with my comments over to the folks at MS Press at the same time I 
mailed my response (last week?), but they haven't responded.

> I suppose it wouldn't be appropriate for Mike to review Mr. Kruglinski's 
book
> (even if he had the time and inclination), being an author himself. 

Indeed: and I feel quite itchy going on as far as I have.  These are just 
facts, though, and not opinion like most book reviews (especially, for 
example, Ron Burk's) are.

.B ekiM
TCHAR sz[] = _T("I do not speak for Microsoft.");




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