Why does new allocate more memory than there is??

Discussion in 'C++' started by Alan Gifford, Oct 17, 2003.

  1. Alan Gifford

    Alan Gifford Guest

    I wrote a program to make sure that new would throw a bad_alloc
    exception if more memory was requested than was available. On my
    system, new allocates up to 2931 MBs of memory (I don't have that
    much, not even with swap) before throwing an exception. When the
    program tries to fill in the allocated memory with data, it is killed
    after using up the available memory.

    Does anyone know why the exception is not being thrown until well
    after all memory has been allocated? Here is the code...

    #include <new.h>
    #include <iostream.h>
    #include <unistd.h>

    #define ARRAY_SIZE1 131072 // # of doubles to take up 1MB of memory
    #define ARRAY_SIZE2 3072 // How many MBs do you want to attempt?

    int main(void) {
    cout << "This is a test to catch for problems with new allocating memory."
    << endl;
    cout << "You might want to watch your memory resource meter."
    << endl;
    sleep(2);

    double* dblPtr[ARRAY_SIZE2];

    cout << "\nAttempting to allocate "
    << ((sizeof(double) * ARRAY_SIZE1 * ARRAY_SIZE2) / (1024 * 1024))
    << " megabytes." << endl;

    int arraySize = ARRAY_SIZE2;
    for (int i=0; i < ARRAY_SIZE2; i++) {
    try {
    dblPtr = new double[ARRAY_SIZE1];
    if (dblPtr == NULL) {
    cout << "\nError, pointer was set to NULL." << endl;
    }
    }
    catch (bad_alloc ex) {
    cout << "\nException caught: " << ex.what() << endl;
    arraySize = i - 1;
    cout << "Setting arraySize to " << arraySize << endl;
    break;
    }
    }

    cout << "\nOstensibly allocated "
    << ((sizeof(double) * ARRAY_SIZE1 * arraySize) / (1024 * 1024))
    << " megabytes of memory." << endl;
    cout << "Let's see what happens when we try to fill it." << endl;
    sleep(2);

    cout << "\nBeginning filling arrays. If the program is killed, it means the"
    << endl;
    cout << "program was not actually able to fill the memory it has been "
    << "allocated." << endl;

    double dummy = 6.67259e-11;
    double* tmp;
    for (int i=0; i < arraySize; i++) {
    tmp = dblPtr;
    for (int j=0; j < ARRAY_SIZE1; j++) {
    tmp[j] = dummy;
    }
    }
    return 0;
    }
     
    Alan Gifford, Oct 17, 2003
    #1
    1. Advertising

  2. Alan Gifford

    cpp_weenie Guest

    "Alan Gifford" <> wrote in message
    news:...
    > I wrote a program to make sure that new would throw a bad_alloc
    > exception if more memory was requested than was available. On my
    > system, new allocates up to 2931 MBs of memory (I don't have that
    > much, not even with swap) before throwing an exception. When the
    > program tries to fill in the allocated memory with data, it is killed
    > after using up the available memory.
    >
    > Does anyone know why the exception is not being thrown until well
    > after all memory has been allocated? Here is the code...
    >
    > #include <new.h>
    > #include <iostream.h>
    > #include <unistd.h>
    >
    > #define ARRAY_SIZE1 131072 // # of doubles to take up 1MB of memory
    > #define ARRAY_SIZE2 3072 // How many MBs do you want to attempt?
    >
    > int main(void) {
    > cout << "This is a test to catch for problems with new allocating

    memory."
    > << endl;
    > cout << "You might want to watch your memory resource meter."
    > << endl;
    > sleep(2);
    >
    > double* dblPtr[ARRAY_SIZE2];
    >
    > cout << "\nAttempting to allocate "
    > << ((sizeof(double) * ARRAY_SIZE1 * ARRAY_SIZE2) / (1024 * 1024))
    > << " megabytes." << endl;
    >
    > int arraySize = ARRAY_SIZE2;
    > for (int i=0; i < ARRAY_SIZE2; i++) {
    > try {
    > dblPtr = new double[ARRAY_SIZE1];
    > if (dblPtr == NULL) {
    > cout << "\nError, pointer was set to NULL." << endl;
    > }
    > }
    > catch (bad_alloc ex) {
    > cout << "\nException caught: " << ex.what() << endl;
    > arraySize = i - 1;
    > cout << "Setting arraySize to " << arraySize << endl;
    > break;
    > }
    > }
    >
    > cout << "\nOstensibly allocated "
    > << ((sizeof(double) * ARRAY_SIZE1 * arraySize) / (1024 * 1024))
    > << " megabytes of memory." << endl;
    > cout << "Let's see what happens when we try to fill it." << endl;
    > sleep(2);
    >
    > cout << "\nBeginning filling arrays. If the program is killed, it means

    the"
    > << endl;
    > cout << "program was not actually able to fill the memory it has been "
    > << "allocated." << endl;
    >
    > double dummy = 6.67259e-11;
    > double* tmp;
    > for (int i=0; i < arraySize; i++) {
    > tmp = dblPtr;
    > for (int j=0; j < ARRAY_SIZE1; j++) {
    > tmp[j] = dummy;
    > }
    > }
    > return 0;
    > }


    A range of virtual addresses is set aside for your use by new, but pages of
    those addresses aren't backed by real storage (either physical mem. or swap)
    until actually touched...

    Hmmm... I just had an interesting thought. If you had been allocating a
    class type with a non-trivial constructor (rather than a double), I suppose
    the memory when have been touched right away during construction of the
    objects and then you would have seen an exception right away.

    Any thoughts on that anyone? Any deeper issues here that I'm not
    considering right off-the-cuff?
     
    cpp_weenie, Oct 17, 2003
    #2
    1. Advertising

  3. Alan Gifford

    Alan Gifford Guest

    "cpp_weenie" <> wrote in message

    > A range of virtual addresses is set aside for your use by new, but pages of
    > those addresses aren't backed by real storage (either physical mem. or swap)
    > until actually touched...
    >
    > Hmmm... I just had an interesting thought. If you had been allocating a
    > class type with a non-trivial constructor (rather than a double), I suppose
    > the memory when have been touched right away during construction of the
    > objects and then you would have seen an exception right away.
    >
    > Any thoughts on that anyone? Any deeper issues here that I'm not
    > considering right off-the-cuff?


    Well, I'm not so much concerned with what goes on behind the scenes to
    create the problem. I guess I am asking why it happens this way. I
    don't really understand the purpose of a bad_alloc exception if it's
    not going to be thrown every time there was a bad allocation attempt.

    I am not an experienced programmer, so I don't know for sure that this
    is the main purpose of the bad_alloc exception, but it certainly seems
    like it is not operating the way it's supposed to.

    Bottom line: I'd just like to know, am I wrong to think that bad_alloc
    should be thrown in this case, or is the compiler doing something
    wrong? I've performed this test on several Linux machines as well as
    a Mac running OS 10.1, and they both have the same error. I was using
    gcc (g++) in all systems.

    Thanks!
    Alan
     
    Alan Gifford, Oct 24, 2003
    #3
  4. Alan Gifford

    Dave Guest

    "Alan Gifford" <> wrote in message
    news:...
    > "cpp_weenie" <> wrote in message
    >
    > > A range of virtual addresses is set aside for your use by new, but pages

    of
    > > those addresses aren't backed by real storage (either physical mem. or

    swap)
    > > until actually touched...
    > >
    > > Hmmm... I just had an interesting thought. If you had been allocating a
    > > class type with a non-trivial constructor (rather than a double), I

    suppose
    > > the memory when have been touched right away during construction of the
    > > objects and then you would have seen an exception right away.
    > >
    > > Any thoughts on that anyone? Any deeper issues here that I'm not
    > > considering right off-the-cuff?

    >
    > Well, I'm not so much concerned with what goes on behind the scenes to
    > create the problem. I guess I am asking why it happens this way. I
    > don't really understand the purpose of a bad_alloc exception if it's
    > not going to be thrown every time there was a bad allocation attempt.
    >
    > I am not an experienced programmer, so I don't know for sure that this
    > is the main purpose of the bad_alloc exception, but it certainly seems
    > like it is not operating the way it's supposed to.
    >
    > Bottom line: I'd just like to know, am I wrong to think that bad_alloc
    > should be thrown in this case, or is the compiler doing something
    > wrong? I've performed this test on several Linux machines as well as
    > a Mac running OS 10.1, and they both have the same error. I was using
    > gcc (g++) in all systems.
    >
    > Thanks!
    > Alan


    I think that your expectations are very reasonable but, nevertheless, I
    don't think you will necessarily see the behavior you expect for the reason
    I stated. I am in total agreement with you that a bad_alloc being thrown
    well after the fact doesn't seem to make a lot of sense. Nevertheless,
    reality is that individual pages may not be backed by actual storage until
    touched. Though you and I find your compiler's behavior illogical, I don't
    believe it is "wrong" in the sense that there is a bug. I think it is
    exhibiting the behavior intended by the compiler writers.

    I'll leave it to others more knowledgeable than I to comment on why pages
    might not be backed by actual storage until they're touched. I'd be very
    interested to know the reason.
     
    Dave, Oct 24, 2003
    #4
  5. Alan Gifford

    tom_usenet Guest

    On 23 Oct 2003 20:13:48 -0700, (Alan Gifford)
    wrote:

    >"cpp_weenie" <> wrote in message
    >
    >> A range of virtual addresses is set aside for your use by new, but pages of
    >> those addresses aren't backed by real storage (either physical mem. or swap)
    >> until actually touched...
    >>
    >> Hmmm... I just had an interesting thought. If you had been allocating a
    >> class type with a non-trivial constructor (rather than a double), I suppose
    >> the memory when have been touched right away during construction of the
    >> objects and then you would have seen an exception right away.
    >>
    >> Any thoughts on that anyone? Any deeper issues here that I'm not
    >> considering right off-the-cuff?

    >
    >Well, I'm not so much concerned with what goes on behind the scenes to
    >create the problem. I guess I am asking why it happens this way. I
    >don't really understand the purpose of a bad_alloc exception if it's
    >not going to be thrown every time there was a bad allocation attempt.
    >
    >I am not an experienced programmer, so I don't know for sure that this
    >is the main purpose of the bad_alloc exception, but it certainly seems
    >like it is not operating the way it's supposed to.
    >
    >Bottom line: I'd just like to know, am I wrong to think that bad_alloc
    >should be thrown in this case, or is the compiler doing something
    >wrong? I've performed this test on several Linux machines as well as
    >a Mac running OS 10.1, and they both have the same error. I was using
    >gcc (g++) in all systems.


    The problem is that bad_alloc doesn't fit well with modern virtual
    paging memory systems. On some systems, for performance reasons,
    memory isn't actually set aside when you call malloc/new, since where
    the pages of memory will come from (disk, main memory, cache?) is only
    decided when you try to access the memory. This makes it impossible
    for the system to know for sure whether it can allocate a chunk of
    memory when you make the allocation, since, e.g., you might deallocate
    another chunk before trying to access this one, thus making room
    available.

    This means that you have to rely on systems other than bad_alloc to
    handle low memory on some modern OSes. On modern OSes, you'll be into
    major performance problems long before you actually run out of memory
    (paging to disk will cause hard disk thrashing), so you need to
    monitor how much memory your program is using and how much is
    available using OS specific functions.

    It's a shame that bad_alloc is largely useless on modern desktop
    platforms.

    Tom
     
    tom_usenet, Oct 27, 2003
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Thomas G. Marshall

    Re: more than 10 seconds to allocate an array!

    Thomas G. Marshall, Aug 28, 2003, in forum: Java
    Replies:
    2
    Views:
    391
    Ahmed Moustafa
    Aug 28, 2003
  2. Andy Flowers
    Replies:
    34
    Views:
    992
    Thomas G. Marshall
    Sep 6, 2003
  3. Jon Skeet
    Replies:
    6
    Views:
    387
    Ahmed Moustafa
    Aug 30, 2003
  4. Mark Thornton
    Replies:
    1
    Views:
    346
    Ahmed Moustafa
    Sep 1, 2003
  5. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,007
    Smokey Grindel
    Dec 2, 2006
Loading...

Share This Page