The Artima Developer Community
Sponsored Link

Weblogs Forum
Jumping from the top of The Parachutes

13 replies on 1 page. Most recent reply: Apr 23, 2005 3:18 AM by indranil banerjee

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 13 replies on 1 page
Matthew Wilson

Posts: 145
Nickname: bigboy
Registered: Jun, 2004

Jumping from the top of The Parachutes (View in Weblogs)
Posted: Apr 17, 2005 11:35 PM
Reply to this message Reply
Summary
(With apologies to Smiths fans) I've been using a technique I call Memory Parachutes for some time. I'm interested in (i) whether I've stolen the technique (& name) from someone else and forgotten, and (ii) what people think of it. It's a simple strategy to increase the chances of a safe-bail-out from low memory conditions
Advertisement
It looks like this (in C++). Note that it's my practice to isolate the outermost catch stuff in main() and have everything program-specific in main_(), so that's where you want to be looking. (Not really sure why, although the fact that I made my project generator do it means I've adhered to the technique. )

As you can see, it's pretty simple. You just allocate a number of different-sized blocks from the C and C++ heap(s) at the start of processing, and release them in the handler for the out-of-memory handler in the hope that you've given back enough that the cleanup code's got better chances than it would otherwise have of performing an orderly shutdown.

The use of different sized blocks is to try and cover the cases where the heap implementation maintains separate pools for small and/or medium and/or large block sizes.

Note that the heterogeneous use of the STLSoft auto_array_destructor and scoped_handle resource wrapper templates leaves something to be desired for neatness and clarity. I've toyed with the idea of writing a parachutes class (with some wiz-bang expression templates!) to do it, but have never yet found the driving motivation. That may depend on the responses to this blog entry. ;)

int main_(int argc, char **argv)
{
  // Allocate the parachutes
  ::stlsoft::auto_array_destructor<char>  parachute1(new char[10]);
  ::stlsoft::auto_array_destructor<char>  parachute2(new char[100]);
  ::stlsoft::auto_array_destructor<char>  parachute3(new char[1000]);
  ::stlsoft::auto_array_destructor<char>  parachute4(new char[10000]);
  ::stlsoft::auto_array_destructor<char>  parachute5(new char[100000]);
  ::stlsoft::scoped_handle<void*>         parachute6(::malloc(10), ::free);
  ::stlsoft::scoped_handle<void*>         parachute7(::malloc(100), ::free);
  ::stlsoft::scoped_handle<void*>         parachute8(::malloc(1000), ::free);
  ::stlsoft::scoped_handle<void*>         parachute9(::malloc(10000), ::free);
  ::stlsoft::scoped_handle<void*>         parachute10(::malloc(100000), ::free);

  try
  {
    // . . . all the business of the application . . . 
  }
  catch(blog_exception &x)
  {
    cout << "You've blogged too much recently, big mouth! Details: " << x.what() << endl;
  }
  catch(another_exception &x)
  {
    cout << "Nasty things have occured! Details: " << x.what() << endl;
  }
  catch(::std::bad_alloc &)
  {
     // Deploy the parachutes with fingers crossed that it leaves enough memory 
     // for the 
     delete [] parachute1.detach();
     delete [] parachute2.detach();
     delete [] parachute3.detach();
     delete [] parachute4.detach();
     delete [] parachute5.detach();
     ::free(parachute6.detach());
     ::free(parachute7.detach());
     ::free(parachute8.detach());
     ::free(parachute9.detach());
     ::free(parachute10.detach());

    // . . . all the actions you want to carry out to (attempt to) effect orderly shutdown . . .

    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}


int main(int argc, char **argv)
{
  // The 'generic' main - carries out a minimum of things, minimising risk
  // of failing to be in a position to 

  try
  {
    return main_(argc, argv);
  }
  catch(::std::exception &x)
  {
    fprintf(stderr, "Unhandled error: %s\n", x.what());
  }
  catch(...)
  {
    fprintf(stderr, "Unhandled unknown error\n");
  }

  return EXIT_FAILURE;
}

The technique is so blindingly obvious that I struggle to accept that I've come up with it independently, but I cannot find any examples of its use in this way. One can google for "memory parachute" but that yields discussions of reserves for main-line use, whereas this is solely for helping, but not guaranteeing, orderly shutdown behaviour.

Enlightenment sought, and sorely needed.


indranil banerjee

Posts: 38
Nickname: indranil
Registered: Nov, 2004

Re: Jumping from the top of the parachutes Posted: Apr 18, 2005 4:37 PM
Reply to this message Reply
Dont mean to pick nits. But catching blog_exception or another_exception would result in EXIT_SUCCESS and skip over the slean up code in the bad_alloc handler.

Perhaps you can have another scope guard to invoke your shutdown code

int main_(int argc, char **argv)
{
// Ensure you cleanup code will always called at the very end (not sure how you do it in stlsoft, im used to using ScopeGuards)
ScopeGuard guard = MakeGuard(::cleanup);

// Allocate the parachutes as before

try
{
// . . . all the business of the application . . .
return EXIT_SUCCESS;
}
catch(blog_exception &x)
{
}
catch(another_exception &x)
{
}
catch(::std::bad_alloc &)
{
// Free up some memory
}

return EXIT_FAILURE;
}

Todd Blanchard

Posts: 316
Nickname: tblanchard
Registered: May, 2003

More commonly known as a rainy day fund Posted: Apr 18, 2005 4:47 PM
Reply to this message Reply
Pick up most any early book on programming the Macintosh from the mid 80's and it will talk about the importance of allocating a big block of memory (commonly referred to as a "rainy day fund") early in a program's life and hanging onto it until you run out of heap, at which point you would consider it to be raining, free the fund and try to continue in a leaner mode until you were able to recover the fund (typically on each pass through the event loop you'd check to see if you could recover the fund).

This technique may be older, but pre-macintosh it was common for developers to not pre-flight operations and simply code as if everything was going to work. They would simply report an error when things didn't. I believe it was the early Apple HIGs that caused the widespread shift in expectations that programs really ought to try harder to be careful with the user's data by preflighting disk writes and memory allocations so you had a better chance of failing gracefully.

Matthew Wilson

Posts: 145
Nickname: bigboy
Registered: Jun, 2004

Re: Jumping from the top of the parachutes Posted: Apr 18, 2005 9:09 PM
Reply to this message Reply
Those classes perform resource management in their dtors, so the memory will be released upon a normal exit from main() (actually main_()).

Matthew Wilson

Posts: 145
Nickname: bigboy
Registered: Jun, 2004

Re: More commonly known as a rainy day fund Posted: Apr 18, 2005 9:11 PM
Reply to this message Reply
> Pick up most any early book on programming the Macintosh
> from the mid 80's and it will talk about the importance of
> allocating a big block of memory (commonly referred to as
> a "rainy day fund") early in a program's life and hanging
> onto it until you run out of heap, at which point you
> would consider it to be raining, free the fund and try to
> continue in a leaner mode until you were able to recover
> the fund (typically on each pass through the event loop
> you'd check to see if you could recover the fund).
>
> This technique may be older, but pre-macintosh it was
> common for developers to not pre-flight operations and
> simply code as if everything was going to work. They
> would simply report an error when things didn't. I
> believe it was the early Apple HIGs that caused the
> widespread shift in expectations that programs really
> ought to try harder to be careful with the user's data by
> preflighting disk writes and memory allocations so you had
> a better chance of failing gracefully.


Thanks for the info. I hadn't come across that as I've not yet had the pleasure - ?!? - of coding for the Mac. Was going to expand my horizons from Win32 & UNIX recently, but things went awry. (And that's a tale for another blog &lt;g>)

Cheers

indranil banerjee

Posts: 38
Nickname: indranil
Registered: Nov, 2004

Re: Jumping from the top of the parachutes Posted: Apr 19, 2005 12:05 AM
Reply to this message Reply
> Those classes perform resource management in their dtors,
> so the memory will be released upon a normal exit from
> main() (actually main_()).

Yes, I assumed auto_array_destructor is an auto_ptr clone that calls delete [] on destruction, and scoped_handle follows the ScopeGuard idiom.

I was refering to the non memory related orderly shutdown code that you had in the bad_alloc handler. That code would get skipped in the other handlers, unless you had non memory related shutdown code intended for the bad_alloc handler alone.

Just a nit, and it was not much to do with the main point of your post. But as others may want to reuse your code I thought I should point it out. I did think the post was very interesting.

The other thing to mention is that if you run out of memory by calling malloc or nothrow new, then the parachutes wont be deployed.

cheers

Matt Gerrans

Posts: 1153
Nickname: matt
Registered: Feb, 2002

Re: Jumping from the top of the parachutes Posted: Apr 20, 2005 8:41 AM
Reply to this message Reply
Or you could just buy more memory. It's a lot cheaper these days. :)

Seriously, with modern OSes, the problem isn't so much running out of memory in the form of failed allocations, but that the system will just bog down with swapping. So it might be more valuable to simply ask the OS how much real RAM vs. virtual is available and deal with "low memory" situations long before allocations fail.

indranil banerjee

Posts: 38
Nickname: indranil
Registered: Nov, 2004

Re: Jumping from the top of the parachutes Posted: Apr 20, 2005 2:52 PM
Reply to this message Reply
> Or you could just buy more memory. It's a lot cheaper
> these days. :)

Ha! Our we've configured our WebLogic server to reserve 1Gb of memory on startup and hold on to it until its weekly restart.

Does it leak? I dont know. More like a college fund than a rainy day fund.

Matt Gerrans

Posts: 1153
Nickname: matt
Registered: Feb, 2002

Re: Jumping from the top of the parachutes Posted: Apr 21, 2005 8:45 AM
Reply to this message Reply
Yikes.

So, what effect did that have? I mean, I assume you were having a crash-and-burn that caused you to start putting the 1GB asside. Does it work? Can the server shut down gracefully now? Does it really need 1GB, or would 1MB be enough? Did you experiment much with it?

Todd Blanchard

Posts: 316
Nickname: tblanchard
Registered: May, 2003

Re: Jumping from the top of the parachutes Posted: Apr 21, 2005 11:08 AM
Reply to this message Reply
"Or you could just buy more memory. It's a lot cheaper these days."

Not really practical if you're developing apps for cell phones though. If you do a little googling on "rainy day fund memory" you'll find a few articles about this technique in reference to embedded programming.

indranil banerjee

Posts: 38
Nickname: indranil
Registered: Nov, 2004

Re: Jumping from the top of the parachutes Posted: Apr 21, 2005 4:24 PM
Reply to this message Reply
Our java app server needs to be up 24/5 with scheduled downtime every weekend. It needs to provide very high thruput the whole time it is running. We found performance was fine most of the time, except when the system needed to perform a full garbage collection, which would kill the system for 15-20 seconds every time.

So the decision was taken to tune the server so that it did not need to perform a full garbage collection during its lifetime. We gave it 1Gb memory so that it could run for a week without a full garbage collection.

Not very pretty, but memory is cheap and we had other things to worry about. There was no problem with system shutdown

Matt Gerrans

Posts: 1153
Nickname: matt
Registered: Feb, 2002

Re: Jumping from the top of the parachutes Posted: Apr 22, 2005 9:11 AM
Reply to this message Reply
I know its not always practical, that was why I included the ":)" part.

Matt Gerrans

Posts: 1153
Nickname: matt
Registered: Feb, 2002

Re: Jumping from the top of the parachutes Posted: Apr 22, 2005 9:13 AM
Reply to this message Reply
So how does gobbling up the 1GB initially help with garbage collection? Seems like it would cause more garbage collection?

Do you have some trigger that occurs when the JVM is about to do garbage collection, you instead free up (all or part of) the 1GB?

indranil banerjee

Posts: 38
Nickname: indranil
Registered: Nov, 2004

Re: Jumping from the top of the parachutes Posted: Apr 23, 2005 3:18 AM
Reply to this message Reply
> So how does gobbling up the 1GB initially help with
> garbage collection? Seems like it would cause more
> garbage collection?

The rule of thumb is the larger the heap, the less frequently GC takes place, but that GC will take longer.

We're talking about full GCs here, the ones that check all the objects in memory. There are also minor GCs that free up recently created objects. Our goal was to allocate enough memory to run for a week without requiring a full GC.

> Do you have some trigger that occurs when the JVM is about
> to do garbage collection, you instead free up (all or part
> of) the 1GB?

We dont respond to JVM events directly. Its more a question of configuring the JVM and letting it run. JVMs are highly configurable beasts these days and JVM tuning is an art in itself. We set the size of the JVM heap, the size of of the new generation and the survivor ratio.

Flat View: This topic has 13 replies on 1 page
Topic: The Fundamental Theorem of Project Management Previous Topic   Next Topic Topic: To new, or not to new, which is the best one?

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use