Re: shared DLL VS static Link, Are they different?



See below...
On Mon, 4 Aug 2008 10:58:27 +0200, "Giovanni Dicanio" <gdicanio@_NOSPAM_email_DOT_it>
wrote:


"Doug Harrison [MVP]" <dsh@xxxxxxxx> ha scritto nel messaggio
news:l1lb94pv2o1616rveu6shcb4qe8cj8to33@xxxxxxxxxx

I would bet the problem is due to the non-MFC DLL loading before the MFC
DLL. This means the non-MFC DLL's static duration data is destroyed after
MFC exits, and if there is any memory that is freed at that time, MFC will
report it as leaked, since it is still allocated when MFC dumps leaks in
its DLL_PROCESS_DETACH. This is a long-standing defect in MFC, which has
no
business dumping leaks; it should wait until the CRT DLL dumps leaks after
all static duration objects have been destroyed. For a workaround, see if
these messages help:

http://groups.google.com/group/microsoft.public.vc.debugger/msg/6b90e68f21529e56

I may be wrong, but I suspect that the aforementioned DLL does some leaks
(OK, these leaks may not be harmful, because they are memory leaks, they are
not non-memory resource leaks e.g. like files; so, being memory leaks, I
think that the OS will free the heap memory after the process is closed).
****
There is a persistent myth that failure to free memory results in memory leakage that
eventually will bring the system down, even though the program that was running has long
since stopped, and even sillier, that running a program that leaks time after time will
cause the system to lose more and more memory.

When a process terminals, ALL RESOURCES OWNED BY THAT PROCESS ARE RELEASED. This means
all memory is freed, all handles used by that process are closed, all GDI resources used
by that process are released, etc.

Note that closing a handle does not release the resources associated with the handle if
another process still has a handle to the object (mutex, semaphore, event, etc.). A file
is not officially closed until *all* handles used by *all* processes are closed, but the
handles used by a process are all closed when the process terminates.

Clipboard data is not owned by the process (in general) but is owned by the system, so it
is not released. The exception is (and from time to time you will get this message)
"thus-and-such a program has data on the clipboard, do you want it left for other
programs?" This is because some programs used deferred clipboard resolution; the data is
not *actually* in the clipboard, but is held by the program itself. If you exit the
program, it will not be able to respond with the data; if you answer "yes" to the
question, it will at that point create the clipboard information and place it in the
clipboard (typically this applies to large images, and that mostly because you are doing
copy-and-paste within the program so it doesn't need to make a copy of the data until you
paste it).

OTOH, a DLL that fails to release memory or other resources it owns can degrade the
performance of the process, if, for example, a sequence of LoadLibrary/FreeLibrary calls
bring it in multiple times and then release it. If the only instance of a handle or
pointer to memory is kept in a variable known only to the DLL and not to the application,
the application cannot free the resource; when the DLL goes away, the only known resource
reference (handle or pointer) disappears. But handles and memory are owned by the
process, and removing the DLL cannot free these resources because the OS does not know or
care that they were allocated in a DLL (this is what DLL_PROCESS_DETACH is all about: if
the DLL allocates resources that only it knows about, it must free them in
DLL_PROCESS_DETACH).

DLL_THREAD_ events are very, very dangerous to depend on. For example, if a FreeLibrary
call is done, the DLL is unloaded if its reference count goes to 0, but not a single
DLL_THREAD_DETACH event happens. So if pointers or handles are kept in TLS, they simply
evaporate in a puff of greasy blue smoke, leaving the resources they reference still
allocated, and generally there is no possible way to free them. Assuming that every
thread has successfully stopped before the DLL is unloaded is a dangerous assumption. I
therefore strongly discourage the belief that DLL_THREAD_DETACH is a reliable mechanism.
IT is fundamentally untrustworthy. I prefer your suggestion of explicit
initialization/cleanup, preferrably NOT done by the caller. For example, the calling
thread calls a Startup routine that returns it a pointer to a data structure (which can be
an LPVOID), and it is the responsibility of the thread to call a Finish routine passing
that same pointer back in to free it. If you don't want the internal structure known, you
can treat it as a "handle" and before returning the pointer, cast it to a handle type, and
when it is passed in, cast it from a handle type back to the pointer type you want; this
gives you a completely opaque data type that can only be used by methods of the DLL, and
cannot be seen or touched internally by the caller.

For example, in my .h file I will add
DECLARE_HANDLE (MYHANDLE)

and write my DLL's interface in terms of MYHANDLE.

MYHANDLE Startup(Some parameters here)
{
LPMYTHING thing = new MYTHING;
...
return (HANDLE)thing;
}

BOOL DoSomething(MYHANDLE h, other parameters here)
{
LPMYTHING thing = (LPMYTHING)h;
...
return some boolean result;
}

void Finish(MYHANDLE h)
{
LPMYTHING thing = (LPMYTHING) h;
delete thing;
}
Now it is really explicit: if your thread doesn't clean up after itself, the thread is
itself erroneous. Nothing magical happens in a DLL_THREAD_DETACH event, and nobody cares
if the DLL gets unloaded; it is a programming error to unload it while there are active
threads, because the threads have to make sure they have properly terminated.

One way to handle this is to have every thread load the DLL:

/* static */ UINT CMyClass::threadfunc(LPVOID p)
{
HANDLE lib = ::LoadLibrary(_T("MyDLL"));
MyFunctions f;
f.Whatever = (WHATEVERFUNC)::GetProcAddress(lib, "Whatever");
f.Thing = (THINGFUNC)::GetProcAddress(lib, "Thing");
... etc.
CMyClass * self = (CMyClass *)p;

self->runthread(f);
::FreeLibrary(lib);
return 0;
}

That way, the DLL cannot be unloaded until every thread terminates (note that it is a
programming error to call ::ExitThread, _endthread, _endthreadex, or similar functions
that can terminate the thread without returning off the top-level thread function. This
works amazingly well.
joe

*****

That DLL is open-source, and if memory allocation tracking (using e.g.
OutputDebugString) is added in internal helper functions icvCreateContext()
and icvDestroyContext(), it seems to me that there are "contexts" create
with icvCreateContext() but not destroyed by icvDestroyContext().

Of course, this is not OP's fault - it's a library problem.

Giovanni


Joseph M. Newcomer [MVP]
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
.



Relevant Pages

  • Re: shared DLL VS static Link, Are they different?
    ... MFC exits, and if there is any memory that is freed at that time, MFC will ... business dumping leaks; it should wait until the CRT DLL dumps leaks after ...
    (microsoft.public.vc.mfc)
  • Re: Why do we need executables in certain formats ?
    ... > complex binary formats was that programs need to be relocated, ... > perhaps linked with libraries. ... Modern virtual memory processors can locate to ... > has a hidden problem with the new .DLL. ...
    (comp.lang.asm.x86)
  • Re: Why is Base3.exe using 700+ K in windows task manager ?
    ... DLL function. ... handles opened by any thread of the calling process ... The DLL allocates memory from the virtual address space of the calling ... Who can tell where memory is really located in a virtual adress space? ...
    (alt.lang.asm)
  • Re: Linking to a .NET dll from C#
    ... for obtaining price quotes and performance is absolutely critical. ... be to use shared memory or memory mapped files. ... Be aware that in these scenarios you're responsible for patching and updates, as the application will no longer rely on the clients machine to keep the framework up to date. ... Determine if a certain managed .NET dll or assembly is loaded ...
    (microsoft.public.dotnet.general)
  • Re: Where did my VB function go?
    ... If the VB application loads the C++ DLL, the DLL gets ... And there is a very common error with shared memory, ... A DLL has a shared memory section. ... series of coherent linked lists local to each attached process. ...
    (microsoft.public.vb.winapi)

Loading