How does std::set_new_handler make more memory available? - c++

From std::set_new_handler
The new-handler function is the function called by allocation functions whenever a memory allocation attempt fails. Its intended purpose is one of three things:
make more memory available
terminate the program (e.g. by calling std::terminate)
throw exception of type std::bad_alloc or derived from std::bad_alloc
Will the following overload gurantees anything ?
void * operator new(std::size_t size) throw(std::bad_alloc){
while(true) {
void* pMem = malloc(size);
if(pMem)
return pMem;
std::new_handler Handler = std::set_new_handler(0);
std::set_new_handler(Handler);
if(Handler)
(*Handler)();
else
throw bad_alloc();
}
}

std::set_new_handler doesn't make memory available, it sets a new-handler function to be used when allocation fails.
A user-defined new-handler function might be able to make more memory available, e.g. by clearing an in-memory cache, or destroying some objects that are no longer needed. The default new-handler does not do this, it's a null pointer, so failure to allocate memory just throws an exception, because the standard library cannot know what objects in your program might not be needed any more. If you write your own new handler you might be able to return some memory to the system based on your knowledge of the program and its requirements.

Here is a working example illustrating the functioning of custom new handlers.
#include <iostream>
#include <new>
/// buffer to be allocated after custom new handler has been installed
char* g_pSafetyBuffer = NULL;
/// exceptional one time release of a global reserve
void my_new_handler()
{
if (g_pSafetyBuffer) {
delete [] g_pSafetyBuffer;
g_pSafetyBuffer = NULL;
std::cout << "[Free some pre-allocated memory]";
return;
}
std::cout << "[No memory to free, throw bad_alloc]";
throw std::bad_alloc();
}
/// illustrates how a custom new handler may work
int main()
{
enum { MEM_CHUNK_SIZE = 1000*1000 }; // adjust according to your system
std::set_new_handler(my_new_handler);
g_pSafetyBuffer = new char[801*MEM_CHUNK_SIZE];
try {
while (true) {
std::cout << "Trying another new... ";
new char[200*MEM_CHUNK_SIZE];
std::cout << " ...succeeded.\n";
}
} catch (const std::bad_alloc& e) {
std::cout << " ...failed.\n";
}
return 0;
}
I do not suggest the demonstrated strategy for production code, it may be too heavy to predict, how many allocations will succeed after your new_handler is called once. I observed some successful allocations on my system (play with the numbers to see what happens on yours). Here's one possible output:
Trying another new... ...succeeded.
Trying another new... ...succeeded.
Trying another new... ...succeeded.
Trying another new... ...succeeded.
Trying another new... ...succeeded.
Trying another new... [Free some pre-allocated memory] ...succeeded.
Trying another new... ...succeeded.
Trying another new... ...succeeded.
Trying another new... ...succeeded.
Trying another new... [No memory to free, throw bad_alloc] ...failed.
Process returned 0 (0x0) execution time : 0.046 s
Press any key to continue.
Instead, from my perspective, do the release of a safety buffer only for terminating your program in a safe way. Even proper exception handling needs memory, if there isn't enough available, abort() is called (as I learned recently).

Related

Is there a memory leak in my machine's implementation of std::exception_ptr, std::current_exception and rethrow_exception?

When running the following code, I see the memory consumption of the process grow. Is there a memory leak in my code, is there a memory leak in the std implementation, or is it intended behaviour? It's running on a Windows 10 machine; both Visual Studio and the task manager show approximately 1MB memory growth per minute.
for (int i = 0; i < 10000; i++) {
std::exception_ptr exptr = nullptr;
std::string errmsg = "some error";
try {
throw std::runtime_error(errmsg.c_str());
}
catch (...) {
exptr = std::current_exception();
}
if (exptr) {
try {
rethrow_exception(exptr);
}
catch (std::exception const& ex) {
exptr = nullptr;
std::cout << ex.what() << std::endl;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(10ms));
}
When directly throwing and logging without delay (without using std::exception_ptr), the memory consumption doesn't grow.
std::exception_ptr is advertised as behaving like a smart pointer, so when resetting it (setting it to nullptr), the underlying resource should be destroyed. Therefore, I expect the underlying exception to be freed appropriately.
I have found out the following: when i copy the code into a fresh project, the memory consumption doesn't grow. I compared the compiler options, and the following compiler option needs to be activated to avoid growing memory consumption: /EHsc
From the msvc compiler documentation i read: [...]The default exception unwinding code doesn't destroy automatic C++ objects outside of try blocks that go out of scope because of an exception. Resource leaks and undefined behavior may result when a C++ exception is thrown.[...] So the growing memory consumption probably was a memory leak.

How to free up a resource used by a function in a googletest ASSERT_THROW statement?

In googletest you can use ASSERT_THROW to test that a certain function throws an error. For instance
ASSERT_THROW(PhysicalPropertyResource p("other/identifier72652"), InappropriateResourceException);
How would you explicitely call another method for releasing some memory used by PhysicalPropertyResource? Normally used like so:
PhysicalPropertyResource p("other/identifier72652");
p.free();
Or should I just not worry about the memory leak since its only in a test and therefore benign. (Its just my OCD to want to keep valgrind completly happy).
I've tried this:
ASSERT_THROW(
PhysicalPropertyResource p("other/identifier72652");
p.free();
, InappropriateResourceException);
}
which doesn't free the memory.
The proper syntax for executing multiple instructions would to wrap them in a block:
ASSERT_THROW({PhysicalPropertyResource p("other/identifier72652");
p.free();},
InappropriateResourceException);
However, this won't help it's not the last line that throws, because then p.free() will not be called. You could create your own "assertion"
void shouldThrow() {
std::unique_ptr<PhysicalPropertyResource> p;
try {
p = std::make_unique<PhysicalPropertyResource>("other/identifier72652");
} catch (const InappropriateResourceException&) {
if (p) //note that this is not possible if it is really constructor that throws
p->free();
return; //test succeeded
} catch (...) {
if (p)
p->free();
FAIL();
}
if (p)
p->free;
FAIL();
}
Note: If you are writing C++ code that uses C library, then your best solution is creation of a RAII wrapper that will take care of resources. If you create a wrapper class, it can free resources in destructor and you will never leak them. You can even write such wrapper for unit tests only, just to avoid this ugly assertion-like code.

operator new, new_handler function in c++

This is pseudocode for the operator new:
while (true)
{
Attempt to allocate size bytes
if (the allocation was successful)
return (a pointer to the memory);
// The allocation was unsuccessful; find out what the
// current new-handling function is
new_handler globalHandler = set_new_handler(0);
set_new_handler(globalHandler);
if (globalHandler)
(*globalHandler)();
else
throw std::bad_alloc();
}
Questions :
1) Why first time 0 is passed as parametr to set_new_handler function?
2) It says that when allocation failed, new_handler function invoked, try to allocate momory and if and only if cant makes more memory, it return pointer to the start of allocated memory or if it cant, it throws bad_alloc exeption or returns null pointer and else body works, which throws a bad_alloc exeption.
My question is why new_handler function sometimes throws exeption, if it can return null pointer and else body would do this ?
1) Why first time 0 is passed as parametr to set_new_handler function?
According to docs this code:
new_handler globalHandler = set_new_handler(0);
set_new_handler(globalHandler);
will
(1) set up handler to null pointer (passed as a parameter)
(2) retrieve function pointer to current handler into globalHandler variable
(3) set up handler back to what it was (whatever globalHandler is pointing to now)
This is performed to retrieve a function pointer to the current handler.
when allocation failed, new_handler function invoked,
try to allocate momory
Unknown. I don't see where it allocates any memory here, as there is no code for it. User is free to do anything inside the new handler, but allocating memory is the last thing I would do. In fact, appropriate behavior would be to release some memory.
and if and only if cant makes more memory, it
return pointer to the start of allocated memory or if it cant, it throws bad_alloc exeption or returns null pointer
Wrong. new_handler does not return anything, it's a typedef to a function pointer accepting no parameters and returning void:
typedef void (*new_handler)();
and else body works, which throws a bad_alloc exeption
else block only works when there is no handler installed (it is null pointer), not when new_handler "fails" or throws an exception or whatever
Read it like this:
void* operator new (std::size_t size, optional blah blah here) blah blah here
{
while(true) // until universe exists (or a nearest power station)
{
// Try to allocate somehow
// Allocation failed
// Retrieved `global_handler` - a pointer to `void (*new_handler)` somehow
if (globalHandler) // global_handler is not null pointer?
{
(*globalHandler)(); // no, invoke it and loop again
}
else
{
throw std::bad_alloc(); // it's null, nothing to do, exception, sorry
}
}
}
See also:
How should I write ISO C++ Standard conformant custom new and delete operators?
This is pre-C++11 code, where the only way to get the current new handler is via the slightly hackish approach of calling set_new_handler to set a new one, which also happens to return the previous handler. Now we have get_new_handler so that we can avoid the set-the-handler-to-null-pointer-to-obtain-the-original-and-then-restore-the-value circumlocution.
In other words,
new_handler globalHandler = set_new_handler(0);
set_new_handler(globalHandler);
is a more convoluted (and more dangerous) way of writing
new_handler globalHandler = get_new_handler();
in C++11.
A new handler's return type is void - it doesn't return a pointer. Actually returning from a new handler (instead of throwing an exception or just terminating the program) essentially means "try again".

catching exception for memory allocation

void newHandler() {
cdebug << "memory allocation failure" << std::endl;
throw std::bad_alloc();
}
int main() {
std::set_new_handler(newHandler);
// ...
}
Once newHandler is established as our error handler, it will be called
when any heap allocation fails. The interesting thing about the error
handler is that it will be called continiously until the memory
allocation succeeds, or the function throws an error.
My question on above text is what does authore mean by " until the memory allocation succeeds, or the function throws an error." How can function can throw an error in this case? Request with example to understand.
Thanks for your time and help.
Basically, your handler may have 3 behavior
It throws a bad_alloc (or its derivate class).
It call exit or abord function which stop the program execution
It return, in which case a new allocation attempt will occur
refs: http://www.cplusplus.com/reference/new/set_new_handler/
This is helpful if you dont want to handle allocation error on each new call.
Depending on your system (using a lot of memory) you can for example free some allocated memory (cache), so the next try memory allocation can be successful.
void no_memory ()
{
if(cached_data.exist())
{
std::cout << "Free cache memory so the allocation can succeed!\n";
cached_data.remove();
}
else
{
std::cout << "Failed to allocate memory!\n";
std::exit (1); // Or throw an expection...
}
}
std::set_new_handler(no_memory);
The intent is that the handler can free some memory, return, and then new() can retry allocation. new() will call the handler as long as the allocation keeps failing. The handler can abort these attempts by throwing bad_alloc(), essentially saying 'I cannot free any more memory, so the allocation can't suceed'.
More details here:
http://www.cplusplus.com/reference/new/set_new_handler/

global handler invokation

I have overloaded new function but unfortunetly never been able to execute global handler for requesting more memory access on my compiler. I also don't understand as per below code snippet if we invoke the
global handler for requesting more memory how it is gling to allocate to P.
I appreciate if anybody can through some light on this
void * Pool:: operator new ( size_t size ) throw( const char *)
{
int n=0;
while(1)
{
void *p = malloc (100000000L);
if(p==0)
{
new_handler ghd= set_new_handler(0);//deinstall curent handler
set_new_handler(ghd);// install global handler for more memory access
if(ghd)
(*ghd)();
else
throw "out of memory exception";
}
else
{
return p;
}
}
}
To have any effect, some other part of the program must have installed a global handler previously. That handler must also have some kind of memory to release when the handler is called (perhaps some buffers or cache that can be discarded).
The default new_handler is just a null pointer, so your code is very likely to end up throwing an exception.
Also, I would have thrown a bad_alloc exception to be consistent with other operator new overloads.
Here are two things to discuss, the first is using new_handler, the second is overloading operator new.
set_new_handler()
When you want use a new_handler, you have to register it. It is typically the first thing to do after entering main(). The handler should also be provided by you.
#include <iostream>
#include <new>
void noMemory() throw()
{
std::cout << "no memory" << std::endl;
exit(-1);
}
int main()
{
set_new_handler(noMemory);
// this will probably fail and noMemory() will be called
char *c = new char[100000000L];
std::cout << "end" << std::endl;
}
When no memory can be allocated, your registered handler will be called, and you have the chance to free up some memory. When the handler returns, operator new will give another try to allocate the amount of memory you requested.
operator new
The structure of the default operator new is something similar you presented. From the point of the new_handler the important part is the while(1) loop, since it is responsible for trying to get memory after called the new_handler.
There is two way out of this while(1) loop:
getting a valid pointer
throwing an exception
You have to have this in mind when you provide a new_handler, because if you can not do anything to free up memory you should deinstall the handler (or terminating or throwing an exception), otherwise you can stuck in an endless loop.
I guess omitting parameter size in your code is just for test purpose.
Also see Scott Meyers' Effective C++ Item 7 for details. As operator new must return a valid pointer even with parameter size = 0, the first thing to do in your operator new should be overwriting size to 1 in case of the user want to allocate 0 number of bytes. This trick is simple and fairly effective.