How to cope with Out of Memory Errors
Hi, I am distributing a desktop application to the general public written in Java 1.4.2. How much memory is required is approximately propertional to how many files they load so Ive tried to pre-emtp OutOfMemoryErrors by checking when memory usage is 95% and preventing the loading of additional files above this level with the following code:
protectedstaticvoid checkMemory()
throws LowMemoryException
{
if (Runtime.getRuntime().freeMemory() < Runtime.getRuntime().maxMemory() * 0.05)
{
Runtime.getRuntime().gc();
if (Runtime.getRuntime().freeMemory() < Runtime.getRuntime().maxMemory() * 0.05)
{
MainWindow.logger.severe("Memory low:" + Runtime.getRuntime().freeMemory() / 1024 / 1024 +"MB");
thrownew LowMemoryException("Running out of memory");
}
}
}
but this code is not robust, sometimes users reports LowMemoryException when the user has only loaded a few files.
I tried removing this code, but then user can get an OutOfMemory error whcih can cause problems with whatever code was running at the time and leave the application in an inconsistent state, if I just exit the application immediately it would be very annoying for users that are int he middle of something.
I also have adjusted the -Xms and -Xmx settings but cannot decide on a suitable default.
What I would ideally like the application to do is to extend its heap space as required upto the limits of the users machine, and if it reaches memory limits handle the lack of memory in a releiable manner allowing the user to continue using the application in a safe way
Sadly, automatic heap expansion is not available. However, you may be able to work around the problem by determining why your application needs to use that much memory. Because no matter how high you set the initial amount of memory, it sounds like your application will fail at some point if the user keeps loading more files.
From this brief description, it seems as if it keeps every file it loads in memory. Is that really needed?
The application uses a datasheet/spreadsheet interface where every record represents a file, I do not need to keep the complete contents of the fie in memory , just some of its meta data.
I expect there are some memory improvements I can make, however heap size will still increase linearly with number of files loaded.
Why is my check code not reliable ?
Unfortunately the metadata is stored displayed within a JTable, so even if If I had in in a Database I think it would all have to be loaded into memory for display within the JTbale in a timely fashion.
Anyway I think Ive found the problem with the original code, it was reporting memory low when almost all the allocated memory was being used but had'nt accounted for the fact that maxMemory limit had not been reached so more memory could be allocated.
I think the correct code is:
protected static void checkMemory()
throws LowMemoryException
{
if (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory() > Runtime.getRuntime().maxMemory() * 0.95)
{
Runtime.getRuntime().gc();
if (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory() > Runtime.getRuntime().maxMemory() * 0.95)
{
MainWindow.logger.severe("Memory low:" + (Runtime.getRuntime().maxMemory() - (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory() ))/ 1024 / 1024 + "MB");
throw new LowMemoryException("Running out of memory");
}
}
}