From: Moshe Matitya (Moshe.Matitya_at_[hidden])
Date: 2006-09-26 04:31:25
Roland Schwarz wrote:
> I fixed the memory leak that showed up on windows when using
> the thread library. The leak indeed was related to tss code
> (oposite to what I believed before).
> This also already has been fixed by Peter Dimov in the HEAD branch.
> However I took a different approach, by having replaced the
> leaking mutex by a CRITICAL_SECTION whose memory is static,
> thus is not subject to heap tracking.
> I did this because in Peters code I see a small chance that
> TlsFree could get into trouble. The on_process_exit could be
> called multiple times. E.g. from userland code before end of
> main _and_ from the tss callbacks. (Of course this could be
> easily cured by use of another once call.)
Actually, according to Richter, a CRITICAL_SECTION *does* dynamically
allocate memory, when InitializeCriticalSection() is called. To
complicate matters further, it may also create an Event kernel object,
when EnterCriticalSection() is called:
"There is a small chance that the InitializeCriticalSection() function
can fail. Microsoft didn't really think about this when it originally
designed the function, which is why the function is prototyped as
returning VOID. The function might fail because it allocates a block of
memory so that the system can have some internal debugging information.
If this memory allocation fails, a STATUS_NO_MEMORY exception is raised.
You can trap this in your code using structured exception handling...
"You can more easily trap this problem using the newer
InitializeCriticalSectionAndSpinCount() function. This function also
allocates the memory block for debugging information but returns FALSE
if the memory could not be allocated.
"Another problem can arise when you use Critical Sections. Internally,
Critical Sections use an Event kernel object if two or more threads
contend for the Critical Section at the same time... Since contention
is rare, the system does not create the Event kernel object until the
first time it is required. This saves a lot of system resources since
most Critical Sections never have contention.
"In a low-memory situation, a Critical Section might have contention,
and the system might be unable to create the required Event kernel
object. The EnterCriticalSection() function will then raise an
EXCEPTION_INVALID_HANDLE exception. Most developers simply ignore this
potential error and have no special handling in their code since this
error is extremely rare. However, if you want to be prepared for this
situation, you do have two options.
"You can use structured exception handling and trap the error. When the
error occurs, you can either not access the resource protected with the
Critical Section or wait for some memory to become available and then
call EnterCriticalSection() again.
"Your other option is to create the Critical Section using
InitializeCriticalSectionAndSpinCount(), making sure that you set the
high bit of the 'dwSpinCount' parameter. When this function sees that
the high bit is set, it creates the Event kernel object and associates
it with the Critical Section at initialization time. If the Event
cannot be created, the function returns FALSE and you can handle this
more gracefully in your code. If the Event is created successfully, you
know that EnterCriticalSection() will always work and never raise an
exception. (Always preallocating the Event kernel objects can waste
system resources. You should do this only if your code cannot tolerate
EnterCriticalSection() failing, if you are sure that contention will
occur, or if you expect the process to be run in very low-memory
-- Programming Applications for Microsoft Windows, 4th Edition
by Jeffrey Richter; Microsoft Press, 1999