DLL question

Started by
12 comments, last by vreality 10 years, 8 months ago

Since it is true that memory of a program thread is integrated, it is not just a "good manner" to free memory allocated in one dll in the same dll. A lot of guru's here, not long ago, said that deleting pointers allocated in a different dll can result in memory leaks (in case of pool usage-a great advance of an mem isolated libs!), plus, it is a definite mark of a useless library, (what you did not create, why would you low level mage it :( ).

If you want to write isolated renderer, I have to stress that the main point of instructions isolation is the memory management safety. Your isolated framework will manage its memory while not allowing usage of the framework for leaking, at least the leaking that will not crush at the very moment (the devils bugs). On your way of writing an isolated library, I encourage you to do following:

1- memory of your library that is exposed to outer dlls, should be passed out by a (read only) pointer!

2- memory of your library that is given from outer dll to create to should be accepted only as a reference to a pointer!

3- memory of your library that is given from outer dll to write to should be avoided, if cannot , pass it by a pointer! (realize that a 99% of such missusage you can replace by point 2-create-write)

4- memory of outer library passed to your library to read from, should be passed as a constant pointer!

Such as:

CLog* log=null;

CDevice* givemedevice=x->CreateDevice(&log);

or:

CDevice* device=null;

StaticUtilities::CreateDevice(&device);

StaticUtilities::DeleteDevice(device); // calls device->Release() if you forgot it, and then deletes the class itself

Remember that main point of isolation is memory management, and memory abusement imediate indicating. Correct isolation allows you to use memory pools, that means, especialy for renderer engines, which operate on large byte arrays tranfered from CPU to GPU, as a massive boost. Actualy your lib will be able to allocate 200MB pool and nearly never use new/delete :), which are quite heavy CPU operations, OS realy does a whole pile of job at them. Of course, the pooling is the last step in lib creation, after you achieve final correct memory isolated ++ library.

Advertisement

No. Your dll will generally be compiled against the same memory manager as the rest of the engine (unless you do something to prevent it), and your engine is linked against the interface you expose from the dll, so generally, the engine can delete objects it gets from the dll.

How does one link against an interface? These preventative methods of which you speak, by that would you mean use an interface?

In my implementation, the engine only handled a single dll specific object - the renderer itself. All other render related objects handled by the engine were defined outside of the dll. They were written in terms of the renderer's interface. All data resources with API specific formats were held within the renderer internally, and referenced externally by ID (so the resource could swap out when the renderer did, without breaking external references).

So basically you've written a C-interface to your DLL, and have wrapped that within a class? Why not just go the whole hog and expose a C-interface instead?

That being said, code defined in the dll, including destructors and anything they call, can only be called while the dll is loaded. So it's a bad idea for the renderer to be handing out objects implemented in the dll.
And yet you hand out a pointer to your renderer? You're just as likely to have a dangling pointer issue with the renderer as with any other class from that DLL, so what makes one class magically safe, and the others unsafe?

A lot of guru's here, not long ago, said that deleting pointers allocated in a different dll can result in memory leaks (in case of pool usage-a great advance of an mem isolated libs!), plus, it is a definite mark of a useless library, (what you did not create, why would you low level mage it sad.png ).

On linux it's perfectly safe to delete memory from other DSO's. On windows, deleting objects created in other DLL's is perfectly safe, so long as the class you're deleting has a virtual destructor. It's pretty easy to catch these errors though, just set your DLL to release, and link it to your debug exe. The debug CRT should throw an exception if you do anything nasty. Tools like VLD/valgrind may also be of use here....

If you want to write isolated renderer, I have to stress that the main point of instructions isolation is the memory management safety.

I don't agree with that statement. The most important thing is making sure you DLL interface is identical in both the DLL and EXE (so no external code in the interface, e.g. STL/boost) Isolating memory allocations is one of the simpler problems to deal with.....

1- memory of your library that is exposed to outer dlls, should be passed out by a (read only) pointer!

In my experience, most people prefer using a mutable pointer to their renderer. A read-only renderer is about as useful as a car with no wheels.

On linux it's perfectly safe to delete memory from other DSO's

As I said, it can fall or not. You can delete a memory set by other module only if assumption that it was created with new operator is true. It usualy isn't,(in pro libs) and it is commonly just a pointer to a pool of the lib , and many other stuff that would couse deleting it illegal (registered library resource and so on). Constructing library that way makes library unable to register, share, pool or anything else all its data, leaving on the user of the library a lot of unsafe dirty work.

Isolating memory allocations is one of the simpler problems to deal with.....

Isolating memory does not mean you delete somewhere else. It means that the module memory, if recreated or freed, does not couse outer program to approach the freed altered memory ever. That is source of spectacular problems. With correct isolation, your outer program will not do that, if all outer structers refer to pointer address of module mem, and not a pointer value. See why direct x is outputing Some** pointers, not Some* pointers to you? If used in correct way, any dx resource that gets freed in dx modules will thus let all outer structers "let know" that memory is not valid anymore. Robust memory isolation can make a C++ library nearly as safe to use as if you were coding in C# or other mem safe language when using it. This is not a marginal quality of a library, but rather the core point of isolation... if you do not achieve it, your isolation attempt will just complicate things up without any benefit.

prefer using a mutable pointer to their renderer.

Do I understand it the way that pointer is provided by renderer (the module) and mutable means they free it or recreate it on their own, as for memory point of view? Well in case of recreating some renderer object, you should call free and create routine of the renderer on the object and get a new constant pointer, where is problem with that?

No.  Your dll will generally be compiled against the same memory manager as the rest of the engine (unless you do something to prevent it), and your engine is linked against the interface you expose from the dll, so generally, the engine can delete objects it gets from the dll.

How does one link against an interface? These preventative methods of which you speak, by that would you mean use an interface?

In visual studio, you would list the dll's corresponding .lib file as a dependancy of the .exe (more on import libraries here).

Doing "something to prevent" the dll from using the same memory manager is not referring to a "preventative measure".  It's referring to situations like implementing your own memory management (e.g., overriding ::new) in your executable and forgetting to make your dll use your override as well.  If you're not doing anything like that, the dynamic linker will link the dll's "new" calls to the same "new" that's called by the .exe.

I suspect that most memory management worries with regard to libraries stem from the practice of publishing them to be used by others in unpredictable situations.  In that case, one must be very careful to ferret out all assumptions about how memory (and other system resources) might be handled on the other side of the .exe-.dll boundary.  Breaking systems of your project out into libraries, as we're discussing here, is not quite the same situation.

You're just as likely to have a dangling pointer issue with the renderer as with any other class from that DLL, so what makes one class magically safe, and the others unsafe?

Quantity and ownership.

If the .exe owns a single .dll exposed object, which owns all other .dll specific resources, it becomes trivial for the .exe to do its part to ensure that they go with the dll when it's unloaded.

If, on the other hand, the dll hands out pointers to dll specific resources, it becomes significantly less trivial to - er - "recall" them all when something decides it's time to swap out the dll.

This topic is closed to new replies.

Advertisement