How to handle dynamic memory allocation failure



  • Hi All,

    How to handle dynamic memory allocation failures in Qt application. If i am allocating memory by using "new" operator and new failed then how to handle its failure.

    eg.
    @
    BorderLayout *layout = NULL;
    layout = new BorderLayout; // if new failed then will it return NULL or throw exception?
    if (NULL == layout)
    {
    // Log error
    return;
    }
    @

    I didn't find any allocation failure handling in Qt sample code.

    Will somebody guide me how to handle allocation failure error?
    Do i have to use "new (std::nothrow)"?

    Regards,
    Meraj Ahmad Ansari



  • There is not much you realistically can do to recover gracefully from such an error, other than crash, AFAIK.





  • yes you can always use standard C++ exception handling if you want.. otherwise, let it just crash.



  • Afaik, most modern compilers use the exception way for out of memory. If you don't like that you have to use the “new (std::nothrow)” notation.
    But handling std::out_of_memory is a bit difficult, because, what do you want to do then? Show a dialog? That also allocates memory. Write a log file? same issue....



  • @Gerolf: If memory allocation failed then i want to gracefully shutdown my app.



  • I think its time to reformulate question- I have some code, guys are initializing pointers by NULL, allocating memory and then they are checking that memory allocation failed or not by comparing pointer with NULL.
    Please check following code -
    @
    CSomeClass* p = NULL;
    p = new CSomeClass;
    if ( NULL != p ) // Is this check relevent???
    {
    // do something
    }
    @

    i think above check does not have any relevence.
    There app is not crashing(by good luck). During code review i found this check useless and their claim is that their memory allocation code is OK.

    So I just want to clarify my doubt as i think we can not assume something during development.


  • Moderators

    To my understanding it is common practice to the pointer for proper assignment.
    One reason could be that new does not stop the application and simply returns a Null pointer. This is certainly possible if someone writes his/her own new operator.

    [quote author="Gerolf" date="1307442082"]
    But handling std::out_of_memory is a bit difficult, because, what do you want to do then? Show a dialog? That also allocates memory. Write a log file? same issue....[/quote]

    I guess std::out_of_memory means usual cases. If you just try allocate a couple of bytes, you are certainly right. However, if by any wrong input the size to be allocated is outside of your standard sizes, you have and may be you want to have the chance to react on the failure.


  • Moderators

    Here is also some reference showing that not only exotic compilers may return a Null.
    http://msdn.microsoft.com/en-us/library/kftdy56f(v=vs.71).aspx

    So I guess it is still good practice to check the return value



  • The point is, it is possible to use no throw new, but by default, MSVS uses throwing new

    bq. Beginning in Visual C++ .NET 2002, the CRT's new function (in libc.lib, libcd.lib, libcmt.lib, libcmtd.lib, msvcrt.lib, and msvcrtd.lib) will continue to return NULL if memory allocation fails. However, the new function in the Standard C++ Library (in libcp.lib, libcpd.lib, libcpmt.lib, libcpmtd.lib, msvcprt.lib, and msvcprtd.lib) will support the behavior specified in the C++ standard, which is to throw a std::bad_alloc exception if the memory allocation fails.


  • Moderators

    Yes, I understand, but a little further down you will find also:

    (4th paragraph) "Even if you use one of the C++ standard library headers, it is possible to get non-throwing new. For example, compile the program below with the following command line and you will not get throwing new behavior, even though standard C++ header files are included: "

    So either you restrict the user not to use /EHsc switch or you should be prepared.

    PS: I am wondering why the "quote" button does not work anymore :-(



  • Only point is it -if you are using new( no std::nothrow functionality) and after allocation checking its return value to NULL. Is it valid ?
    If we are not using std::nothrow then it will not return NULL and subsequent call will crash. But if we are using std::nothrow and checking NULL then developer can take preventive actions(eg. gracefully shutdown).


  • Moderators

    To my understanding, yes.
    With checking the pointer for its return value you are more on the save side. You are independent of the actual default setting of your compiler. Also in case someone is changing some switches as possible with the ms compiler, you should be save. However, in case of new with throwing option, you might want to add the functionality catching the out of memory event. This allows you in such cases a graceful shutdown.

    Ultimatively, one needs to decide to wear your pants with a belt, with suspenders or with both. ;-)



  • [quote author="Gerolf" date="1307442082"]But handling std::out_of_memory is a bit difficult, because, what do you want to do then? Show a dialog? That also allocates memory. Write a log file? same issue....[/quote]

    There is one thing you can actually do in applications that absolutely have to shutdown gracefully - request a block of memory at startup which serves as an "emergency heap" in case you run out of memory during runtime and use "placement new":http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10 or - if you need support for creating Qt objects too - "custom global allocators":http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.14.

    Thus you can still create objects on the heap including a nifty QMessageBox if you want to.



  • [quote author="Meraj Ahmad Ansari" date="1307516970"]Only point is it -if you are using new( no std::nothrow functionality) and after allocation checking its return value to NULL. Is it valid ?
    If we are not using std::nothrow then it will not return NULL and subsequent call will crash. But if we are using std::nothrow and checking NULL then developer can take preventive actions(eg. gracefully shutdown).[/quote]

    It is not possible that new returns something else than 0 if it can't allocate memory.

    return 0

    throw exception (nothing is returned, variable is not changed)

    If it is throwing, you will not continue as usual, as you have to catch the exception.



  • [quote author="Lukas Geyer" date="1307521825"][quote author="Gerolf" date="1307442082"]But handling std::out_of_memory is a bit difficult, because, what do you want to do then? Show a dialog? That also allocates memory. Write a log file? same issue....[/quote]

    There is one thing you can actually do in applications that absolutely have to shutdown gracefully - request a block of memory at startup which serves as an "emergency heap" in case you run out of memory during runtime and use "placement new":http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10 or - if you need support for creating Qt objects too - "custom global allocators":http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.14.

    Thus you can still create objects on the heap including a nifty QMessageBox if you want to.[/quote]

    Very interesting idea, but are you sure it would work? I mean: new-ing a messagebox will not just create that message box, but the message box in turn will new other (child) objects. You have no control over how that happens; there is no way you can use placement new or something like that for it, I think? You may be able to write a message into a logfile manually or something like that, but I doubt you could do much more than that. Still, the solution is certainly interesting!



  • bq. @koahnig; ....Also in case someone is changing some switches as possible with the ms compiler,.....

    I only want to discuss it under gcc (QtCreator). Does QtCreator support switches? No doubt Visual Studio is really great

    bq. @Gerolf : If it is throwing, you will not continue as usual, as you have to catch the exception.

    currently my code base is very large and unfortunately with out exception handling and that is why i am thinking about std::nothrow

    Thanks to all guys for your support.


  • Moderators

    [quote author="Meraj Ahmad Ansari" date="1307529893"]bq. @koahnig; ....Also in case someone is changing some switches as possible with the ms compiler,.....

    I only want to discuss it under gcc (QtCreator). Does QtCreator support switches? No doubt Visual Studio is really great
    [/quote]
    I am not an expert on QtCreator, but almost everything can be changed on the project's tap. Unfortunately, you have to dig sometimes into the details of a couple of tools.



  • [quote author="Andre" date="1307523827"]
    [quote author="Lukas Geyer" date="1307521825"]
    There is one thing you can actually do in applications that absolutely have to shutdown gracefully - request a block of memory at startup which serves as an "emergency heap" in case you run out of memory during runtime and use "placement new":http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10 or - if you need support for creating Qt objects too - "custom global allocators":http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.14.

    Thus you can still create objects on the heap including a nifty QMessageBox if you want to.[/quote]

    Very interesting idea, but are you sure it would work? I mean: new-ing a messagebox will not just create that message box, but the message box in turn will new other (child) objects. You have no control over how that happens; there is no way you can use placement new or something like that for it, I think? You may be able to write a message into a logfile manually or something like that, but I doubt you could do much more than that. Still, the solution is certainly interesting!

    [/quote]

    I initially came up with three solutions:

    Reserve a bunch of memory at startup and release it when neccessary to gain memory

    Reserve a bunch of memory at startup and use it directly as "heap replacement" using placement new

    Reserve a bunch of memory at startup and use it directly as "heap replacement" by overloading the global new operator or setting a new handler using std::set_new_handler

    It would not prefer 1. because you cannot guarantee that the operating system will return the memory you just freed back to your application (most likely it won't if free memory is rare).

    I prefer 2., which usually works flawlessly, provided that your allocation code does so (keyword memory alignment) ;-)

    I personally never used 3., because if you usually run out of memory your system is thrashing anyways long before and the application should shut down as soon as possible (without any user interaction). Nevertheless it should work by replacing the global operator new with your own memory management code which can switch between system memory and "emergency memory".

    @
    // class.h
    #ifndef CLASS_H
    #define CLASS_H

    class Class
    {
    public:
    Class();
    };

    #endif // CLASS_H

    // class.cpp
    #include "class.h"

    Class::Class()
    {
    int* pointer = new int;
    }

    // main.cpp
    #include "class.h"

    void* operator new(size_t size)
    {
    // Implementation goes here
    }

    void operator delete(void* pointer)
    {
    // Implementation goes here
    }

    int main(int argc, char argv[])
    {
    Class
    pointer = new Class;

    return 0;
    

    }
    @

    Executing the example above shows that both situations are handled correctly (the custom global new operator is called twice); creating objects outside and inside classes.

    Setting a new handler using std::set_new_handler which should be called in case of no-new-memory-situations should do the same trick, as it is allowed to either throw an bad_alloc exception or terminate the application or allocating and returning memory somewhere else, for example at our "emergency heap". I think this is the preferred solution for 3. (when having no global / static objects, where you cannot guarantee that std::set_new_handler has been already executed), as you do not have to mess with the global new operator.

    Please keep also in mind, that even if new is returning a valid pointer (not returning null) this does not mean that there is actually memory available for the application. If I remember correctly new on Linux systems always returns a valid pointer, as memory is acquired on access, not on allocation!

    So the following snippet will crash even due to proper error handling
    @
    int* integer = new int;
    if(integer != 0)
    {
    *integer = 42; // crash
    }
    @

    Question is, does the runtime call the function set by std::set_new_handler in this case? Never tried that.


  • Moderators

    [quote author="Lukas Geyer" date="1307537741"]
    Please keep also in mind, that even if new is returning a valid pointer (not returning null) this does not mean that there is actually memory available for the application. If I remember correctly new on Linux systems always returns a valid pointer, as memory is acquired on access, not on allocation!

    So the following snippet will crash even due to proper error handling
    @
    int* integer = new int;
    if(integer != 0)
    {
    *integer = 42; // crash
    }
    @

    Question is, does the runtime call the function set by std::set_new_handler in this case? Never tried that.[/quote]

    But what sense would the check of the pointer make then?

    BTW: Is it just in my browser that the last paragraph after the example is NOT shown in the original post?
    I just came across it when quoting the post.


  • Moderators

    [quote author="koahnig" date="1307539373"]
    BTW: Is it just in my browser that the last paragraph after the example is NOT shown in the original post?
    I just came across it when quoting the post.[/quote]

    Forget that part. Suddenly the text was there when I had posted my reply.
    @Lukas Was your original post updated?



  • [quote author="koahnig" date="1307539373"]
    But what sense would the check of the pointer make then?
    [/quote]

    No sense, because the pointer returned by new will never be 0.
    Even if you override the operator new the compiler won't let you return 0.

    [quote author="koahnig" date="1307539373"]
    BTW: Is it just in my browser that the last paragraph after the example is NOT shown in the original post?
    [/quote]
    [quote author="koahnig" date="1307539373"]
    Forget that part. Suddenly the text was there when I had posted my reply.
    @Lukas Was your original post updated?
    [/quote]

    This might be the reason ;-)



  • [quote author="Lukas Geyer" date="1307537741"]
    Please keep also in mind, that even if new is returning a valid pointer (not returning null) this does not mean that there is actually memory available for the application. If I remember correctly new on Linux systems always returns a valid pointer, as memory is acquired on access, not on allocation!

    So the following snippet will crash even due to proper error handling
    @
    int* integer = new int;
    if(integer != 0)
    {
    *integer = 42; // crash
    }
    @
    [/quote]

    This would mean that Linux is not implementing the C++ standard, I can't beleive that.



  • [quote author="Gerolf" date="1307556594"]
    This would mean that Linux is not implementing the C++ standard, I can't beleive that. [/quote]

    It is called overcommit. The address space is expanded immediately but physical memory pages are assigned at the moment the memory is accessed. If there are none, your process or any other process is silently killed by the kernel, depending on the selected strategy.

    I have to admit that i don't know if anything has changed in recent kernel versions, but usually overcommit is enabled. The behaviour can be controlled using the vm.overcommit_memory sysctl or /proc/sys/vm/overcommit_memory where you can only restrict, but not disable overcommit.

    I've read an article about it just a few days ago. I'll see if i can find it.



  • Quoting [i386] linux-2.6.38/Documentation/vm/overcommit-accounting

    @
    The Linux kernel supports the following overcommit handling modes

    0 - Heuristic overcommit handling. Obvious overcommits of
    address space are refused. Used for a typical system. It
    ensures a seriously wild allocation fails while allowing
    overcommit to reduce swap usage. root is allowed to
    allocate slighly more memory in this mode. This is the
    default.

    1 - Always overcommit. Appropriate for some scientific
    applications.

    2 - Don't overcommit. The total address space commit
    for the system is not permitted to exceed swap + a
    configurable percentage (default is 50) of physical RAM.
    Depending on the percentage you use, in most situations
    this means a process will not be killed while accessing
    pages but will receive errors on memory allocation as
    appropriate.
    @

    On LMDE 2.6.32-5-amd64 for example, which is based on debian testing, heuristic overcommit handling is enabled per default.



  • Thanks for the info, very interesting...


  • Moderators

    That is really interesting. However it cannot comply with new(nothrow). As Lukas has pointed out, the check of the pointer will not work. So there should be also a mechanism to secure the situation. Is anybody aware, that a compiler complains when the new (nothrow) is used?



  • bq. koahnig: Is anybody aware, that a compiler complains when the new (nothrow) is used?

    If i understand you clearly then my observation is - when i used std::nothrow with new and if memory allocation failed then it is returning NULL, safe way to handle memory allocation failure. Also compiler(i tested on Ubuntu/Qt 4.7) has no issue.

    @char *buffer = new (std::nothrow) char[LARGE_MEMORY_CHUNK];
    if ( NULL == buffer )
    {
    //terminate gracefully
    }@


  • Moderators

    Thanks for your verification of the issue and your reply.
    I will have an eye on it as well next time.



  • [quote author="Meraj Ahmad Ansari" date="1307703395"]If i understand you clearly then my observation is - when i used std::nothrow with new and if memory allocation failed then it is returning NULL, safe way to handle memory allocation failure. Also compiler(i tested on Ubuntu/Qt 4.7) has no issue.

    @char *buffer = new (std::nothrow) char[LARGE_MEMORY_CHUNK];
    if ( NULL == buffer )
    {
    //terminate gracefully
    }@
    [/quote]

    This is possibly due to
    @
    0 - Heuristic overcommit handling. ... It
    ensures a seriously wild allocation fails while allowing
    overcommit to reduce swap usage. ...This is the default.
    @

    If you absolutely have to ensure that your application recovers from out of memory situations (working both on Linux and Windows) you will have to use either

    • std::nothrow and the null check consistently or
    • set a new handler, which should be called even with exceptions disabled (/EHsc)

    In addition, you should include Linux specific code which

    • disables overcommit (vm.overcommit_memory = 2) which might lead to thrashing and
    • instructs the kernel to not kill your process in case of out of memory (/proc/self/oom_score_adj = -17), which is an absolute must because even if your process does not run out of memory he might be selected by the kernel oom killer and will be assassinated without any notice.

    And you should reserve enough "emergency memory" at startup when needed, because if there is no memory the kernel can't give you some.

    Of course none of this procedures will save you from kernel panics or power outages - so you should possibly add some disaster recovery code to your list ;-)

    In my opinion a standard application should

    • not use std::nothrow and null checks because this absolutely bloats your code in every single way
    • set a new handler or use an (outermost) exception handler which handles out of memory situations (by saving the current state and exiting)


  • bq. Lukas Geyer wrote.. In my opinion a standard application should

    • not use std::nothrow and null checks because this absolutely bloats your code in every single way
    • set a new handler or use an (outermost) exception handler which handles out of memory situations (by saving the current state and exiting)

    Just a query Lukas-

    you have function and you are allocating some runtime memory in it. At some point of time allocation failed and your new handler function get called. Then how you deallocate pre allocated memory in function. Check following code snippet -

    @
    void method()
    {
    SomeClass1* obj1 = new SomeClass1;
    // allocation is successful and call some
    // function with obj1 , every thing fine upto this point

    SomeClass2* obj2 = new SomeClass2;
    obj2->SomeFunctionCall(); //Suppose allocation failed and your new handler function get called
    // My question is how you are going to deallocate "obj1" memory?
    }
    @



  • @Meraj: One option would be to use smart pointers. Or to declare the relevant pointers outside the try catch block.

    Btw.. is the original question solved? Simplistically, if the system's out of memory, we should just gracefully quit, or give an error. Usually, one can just look at the code of new (its mostly just about 10-15 lines of handling). The allocation is best done in a try catch block if you fear an exception is going to occur in allocation. I'm not sure about the pointer returned, but that could probably be inferred from the implementation of new.

    "Smart pointers in Qt":http://labs.qt.nokia.com/2009/08/25/count-with-me-how-many-smart-pointer-classes-does-qt-have/



  • bq. jim_kaiser wrote .. The allocation is best done in a try catch block if you fear an exception is going to occur in allocation.

    Have you tried it in Qt (specially on Linux)? if you are using try/catch block and an out of memory exception occurs, does your catch block hits? Certainly not in normal exception handling.

    bq. jim_kaiser wrote .. Btw.. is the original question solved?

    Frankly speaking I never considered it as a question. I really want to know What type of technique other developers are using.



  • bq. Have you tried it in Qt (specially on Linux)? if you are using try/catch block and an out of memory exception occurs, does your catch block hits? Certainly not in normal exception handling.

    Honestly, I have never had to use it or rather test it.. specifically because running out of memory is not a concern in my project. I will test it on Windows and Linux in Qt and let you know. Though i do find it strange that the out of memory exception is not caught but i'm just talking about pure C++. I could be mistaken but why should it be any different with Qt objects, when the 'operator new' used is the same?

    On Windows MSVC2005
    @
    void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
    { // try to allocate size bytes
    void *p;
    while ((p = malloc(size)) == 0)
    if (_callnewh(size) == 0)
    { // report no memory
    static const std::bad_alloc nomem;
    _RAISE(nomem);
    }

        return (p);
        }
    

    @

    The code here quite clearly returns 0 or valid pointer or throws a std::bad_alloc exception. But the concerns about lazy allocation and returning a valid pointer without allocation could be valid depending on the platform.

    bq. Frankly speaking I never considered it as a question. I really want to know What type of technique other developers are using.

    Okay, thanks for clearing that. I found the ideas quite insightful too, the approach with reserving emergency memory at the start of execution is a nice approach.



  • [quote author="Meraj Ahmad Ansari" date="1307953504"]
    Frankly speaking I never considered it as a question. I really want to know What type of technique other developers are using.[/quote]

    As I think this is directly related to your last question I'll answer right here.

    To me, there are usually two types of heap allocations in an application:

    small, but frequent allocations required for the program to flow, like creating widgets or objects on the heap for the user interface or eg. network processing

    large, but infrequent allocations required for some specific tasks and not necessarily required for the program to flow, like a buffer for loading eg. a large image into memory which has been selected by the user in an image processing application

    The way you react to out of memory situations will differ for both types.

    1. I see no way a program can or should recover from such situations. It should save any data which has to be saved to a persistent storage and then exit. For this task, you will usually need just a limited amount of information, which then has - of course - to be available to your new handler / exception handler. This allows you to handle out of memory situations at a single point in your code.

    Usually the required information is available through your "design" anyways, because you'll need it for your normal program flow too (eg. Application::instance()->openedImage()->data() to stay at our image processing application example). There is no need to access all the other data not relevant for you recovery code, especially there is no need to delete anything because your application gets aborted anyways.

    However, if you need to allocate further memory in your recovery code you should have reserved some already (the "emergency heap" discussed earlier).

    1. There is no need to abort the application in such situations. Allocations failures can be caught using std::nothrow and a null pointer check or local exception handling.

    Probably my last post was a bit misleading. Of course there are situations where it is absolutely legitimate to use a std::nothrow / null pointer check, but you should not guard every single allocation with it.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.