How to avoid MATLAB crash when opening too many figures?

Jonas Heidelberg picture Jonas Heidelberg · Jun 1, 2011 · Viewed 9.3k times · Source

Sometimes I start a MATLAB script and realize too late that it is going to output way too many figures. Eventually I get an

Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space

which can easily be reproduced on my machine using

for i=1:inf
  figure;
end

I get to around ~90 figures before it crashes with the standard setting (Preferences / Java Heap Memory) of 128 MB Java heap, while doubling the Heap to 256 MB gives me around 200 figures.

Do you see any way to avoid the Java error message? If there is not enough memory for another figure, I'd like my script to be told rather than crash.

Maybe I could have a wrapper for figure which (somehow?) checks how much Java heap is available and which refuses to open a new figure if there is not enough space left?

Update

Using the answers below, I get a nice graph for how much free Memory Java has:

figure;plot(freeMem/1E6,'x');ylabel('java.lang.Runtime.getRuntime.freeMemory [MB]');xlabel('number of empty figures created');

This was produced using

for i=1:inf
    java.lang.Runtime.getRuntime.gc
    fprintf('%3.0f: %1.0f Byte free\n',i,java.lang.Runtime.getRuntime.freeMemory);
    figure;
end

I assume the increase in the beginning means that garbage collection only does a certain effort every time I call it?

Update 2 - my solution

Using the help I got here, I implemented the following solution as a figure.m which overloads and calls the build-in figure command:

function varargout=figure(varargin)
memcutoff = 10E6; % keep at least this amount of bytes free
memkeyboard= 3E6; % if memory drops below this, interrupt execution and go to keyboard mode
global refuse_new_figures
if refuse_new_figures
    warning('jb:fig:lowjavamem2','Java WAS memory low -> refusing to create a new figure. To reset, type "global refuse_new_figures ; refuse_new_figures = [];"');
    return
end
freemem=java.lang.Runtime.getRuntime.freeMemory;
if freemem < memcutoff 
    fprintf('Free memory is low (%1.0f Bytes) -> running garbace collector...\n',freemem);
    java.lang.Runtime.getRuntime.gc
end
freemem=java.lang.Runtime.getRuntime.freeMemory;
% fprintf('Free memory is %1.0f Bytes.\n',freemem);
if freemem < memkeyboard
    warning('jb:fig:lowjavamem','Java memory very low -> going into interactive mode. Good luck!');
    keyboard;
end
if freemem < memcutoff
    warning('jb:fig:lowjavamem','Java memory low -> refusing to create a new figure!');
    refuse_new_figures=true;
else
    if nargin > 0
        if nargout > 0
            varargout{1}=builtin('figure',varargin{:});
        else
            builtin('figure',varargin{:});
        end
    else
        if nargout > 0
            varargout{1}=builtin('figure');
        else
            builtin('figure');
        end
    end
end

Answer

Jonas picture Jonas · Jun 1, 2011

In general, I'd suggest setting maximum Java Heap Memory to about 25% of the available RAM, which allows you to open lots of figures (but not infinite numbers). If you cannot do this in the preferences (e.g. b/c you have a Mac like mine), this solution will help - it overrides the preference settings.

The linked solution also tells you how much free java memory you have left, and how much total is available: Run the following commands:

java.lang.Runtime.getRuntime.maxMemory
java.lang.Runtime.getRuntime.totalMemory
java.lang.Runtime.getRuntime.freeMemory 

Unfortunately, a figure doesn't take a fixed amount of Java memory, an empty figure takes much less than one displaying 10k points, and a minimized figure takes less memory than a maximized one. However, if you can estimate the average memory needed per figure, you can indeed write a wrapper for figure that checks whether it's likely that this figure will be the last. Alternatively/additionally, you could make the wrapper function minimize all other figures (see Undocumented Matlab for this).

EDIT As pointed out by @Peter Lawrey, you may also try and perform garbage collection before checking how much memory is available - though I don't know whether Matlab would try that, anyway.