Previous header: "Must I replace global operators new and delete to change memory allocation strategy in third party code?"
Short story: We need to replace memory allocation technique in third-party library without changing its source code.
Long story:
Consider memory-bound application that makes huge dynamic allocations (perhaps, almost all available system memory). We use specialized allocators, and use them everywhere (shared_ptr
's, containers etc.). We have total control and power over every single byte of memory allocated in our application.
Also, we need to link against a third-party helper library. That nasty guy makes allocations in some standard way, using default operators new
, new[]
, delete
and delete[]
or malloc
or something else non-standard (let's generalize and say that we don't know how this library manages it's heap allocation).
If this helper library makes allocation that are big enough we can get HDD thrashing, memory fragmentation and alignments issues, out-of-memory bad_alloc
s and all sorts of problems.
We can not (or do not want) to change library source code.
First attempt:
We never had such unholy "hacks" in release builds before. First test with overriding operator new
works fine, except that:
- we do not know what gotchas wait us in the future (and this is awful)
- our users (and even our allocators) now have to allocate same way that we do
Questions:
- Are there ways to hook these allocations without overloading global operators? (local lib-only hooks?)
- ...and if we don't know what exactly it uses:
malloc
ornew
? Is this list of signatures complete? (and there are no other things that we must implement):
void* operator new (std::size_t size) throw (std::bad_alloc); void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) throw(); void* operator new (std::size_t size, void* ptr) throw(); void* operator new[] (std::size_t size) throw (std::bad_alloc); void* operator new[] (std::size_t size, const std::nothrow_t& nothrow_value) throw(); void* operator new[] (std::size_t size, void* ptr) throw(); void operator delete (void* ptr) throw(); void operator delete (void* ptr, const std::nothrow_t& nothrow_constant) throw(); void operator delete (void* ptr, void* voidptr2) throw(); void operator delete[] (void* ptr) throw(); void operator delete[] (void* ptr, const std::nothrow_t& nothrow_constant) throw(); void operator delete[] (void* ptr, void* voidptr2) throw();
Something different if that library is dynamic?
Edit #1
Cross-platform solution is preferable if possible (looks like not very possible). If not, our major platforms:
- Windows x86/x64 (msvc 10)
- Linux x86/x64 (gcc 4.6)
Edit #2
Almost 2 years have passed, few OS and compiler versions have evolved, so I am curious if there is something new and unexplored in this area? Any standard proposals? OS-specifics? Hacks? How do you write memory-thirsty applications today? Please share your experience.
main
gets the privilege of overloading operator new/delete and nobody else. Otherwise you're just building in run time errors for when somebody accidentally transfers memory ownership across a border they shouldn't have. Sorry to be the bearer of bad news. – Gunillanew
was just a first thing that comes in mind and I would be glad to avoid it. Maybe there is a technique to cut the "nasty" allocations somewhere else? Maybe we can sandbox library's heap somehow? We are looking for broad area of solutions. – Caloric