How to avoid MATLAB crash when opening too many figures?
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:
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开发者_C百科
if nargout > 0
varargout{1}=builtin('figure');
else
builtin('figure');
end
end
end
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.
You can check the free memory, if there is no enough trigger a GC and check again. If there is still not enough, fail. You might want to allow 1-10 MB head room.
You can use Runtime.gc() and Runtime.freeMemory();
If you don't set the maximum memory it will make it a percentage of the available memory.
I use the findobj function in my own function 'limfig', where imglimit sets the amount of figures you want to be allowed to open at one time.
function y=limfig
imglimit=15;
if length(findobj('type','figure'))<imglimit
y=figure;
else
'too many figures already open'
return
end
end
Save this short code as limfig.m and then in any other code use the line f=limfig instead of f=figure.
精彩评论