try...catch for memory full error in imaq toolbox ?
7 views (last 30 days)
Show older comments
Hi,
I am recording data with an usb3vision camera. I am directly capturing to RAM. After a while, the memory of the computer is full and capturing stops. I would like to catch this error and display a msgbox. This is the code I am testing:
clc
imaqreset
delete(imaqfind); %clears all previous videoinputs
hwinf = imaqhwinfo;
info = imaqhwinfo(hwinf.InstalledAdaptors{1});
industrial_camera_name = info.DeviceInfo.DeviceName;
industrial_camera_supported_formats = info.DeviceInfo.SupportedFormats;
industrial_camera_vid = videoinput(info.AdaptorName,info.DeviceInfo.DeviceID,'Mono8');
industrial_camera_settings = get(industrial_camera_vid);
industrial_camera_settings.Source.ExposureTime =20;
industrial_camera_vid.FramesPerTrigger = 10000;
flushdata(industrial_camera_vid);
try
start(industrial_camera_vid);
%wait(industrial_camera_vid);
while industrial_camera_vid.FramesAcquired < industrial_camera_vid.FramesPerTrigger
pause(1)
disp(num2str(industrial_camera_vid.FramesAcquired))
end
catch ME
imaqreset
if strcmpi(ME.identifier,'imaq:imaqmex:outofmemory')
msgbox('Out of memory. RAM is full, most likely, you need to lower the amount of frames to capture to fix this error.','modal');
end
if strcmpi(ME.identifier,'imaq:wait:timeout')
msgbox('Image capture timeout. Most likely, memory is full and you need to lower the amount of frames to capture to fix this error. It is also possible that the synchronization cable is not plugged in correctly.','modal');
end
end
The problem is that the while loop never stops, even if the image capture crashes due to full RAM. How can I stop the while loop and display a proper error message?
This is how my output looks like, the while loop keeps on running:
3870
4031
4192
4353
4514
4675
Error event occurred at 16:38:40 for video input object: Mono8-gentl-1.
Unable to allocate memory for an incoming image frame due to insufficient free physical memory.
Unable to allocate memory for an incoming image frame due to insufficient free physical memory.
Error in memory_full (line 18)
pause(1)
4754
4754
4754
4754
4754
0 Comments
Answers (4)
Image Analyst
on 3 Apr 2023
Perhaps put the try catch INSIDE the while loop. Then in the catch, put a break to kick it out of the loop if an error was thrown.
start(industrial_camera_vid);
while industrial_camera_vid.FramesAcquired < industrial_camera_vid.FramesPerTrigger
try
%wait(industrial_camera_vid);
pause(1)
disp(num2str(industrial_camera_vid.FramesAcquired))
catch ME
% Some error occurred if you get here.
imaqreset
if strcmpi(ME.identifier,'imaq:imaqmex:outofmemory')
uiwait(msgbox('Out of memory. RAM is full, most likely, you need to lower the amount of frames to capture to fix this error.','modal'));
end
if strcmpi(ME.identifier,'imaq:wait:timeout')
uiwait(msgbox('Image capture timeout. Most likely, memory is full and you need to lower the amount of frames to capture to fix this error. It is also possible that the synchronization cable is not plugged in correctly.','modal')));
end
break; % out of while loop.
end
end
9 Comments
dpb
on 3 Apr 2023
"I don't understand how, but I'll try to find a way..."
Find the default imagcallback function and look at it -- you'll see it's what is outputting the error messages you're getting; set a breakpoint in it and you'll be able to see the object and data that it receives.
Use the function as a pattern; I think what you'll want to do is to have your replacement return a flag variable that can test inside the while loop and break as @Image Analyst suggests; what the default does is just display the error info to the command window; you need it to do something more than that; return a value that you can check and take action on.
Or, depending upon the needs of the application; you could have it do the stop acquisition and so on there; just that you would then probably(?) need a global parameter to use as the control variable for the while loop to turn it off...just what/how to construct it depends on what is wanted to be done.
Bruno Luong
on 3 Apr 2023
To my knowledge there is no simple way to detect memory issue.
What you ask MATLAB, e.g., using command such as
[~,sys] = memory;
membytes = sys.PhysicalMemory.Available; % bytes
I will always report a positive number, even if there is memory runs out since it will swap on HD if you requires MATLAB to allocate array. And when there is NO physical RAM available for instanant the acquisition SW to run correctly there is buffer overrun and it can result crashes. The best thing is to monitor membytes long before and detect when it is no longer reduced and low. It is a sign that the RAM starts to runout and you have to anticipate and stop the acquisition before it crashes.
0 Comments
William Thielicke
on 3 Apr 2023
2 Comments
Bruno Luong
on 4 Apr 2023
Edited: Bruno Luong
on 4 Apr 2023
What surprise me in your log is that the acquisition crashes when free memory is 1.7 Gb. It's a wild guess but it looks to me like the whole video buffer are reallocate each time a new frame arrive. Are you surre the acquisition is called correctly as by the vendor recommendation?
If the buffer is reallocated then you should not monitor the RAM, but the largest contiguous block avalable as dpb suggests.
dpb
on 4 Apr 2023
Edited: dpb
on 4 Apr 2023
Well, you probably can manage to do it from the above, but it's peculiar as Bruno notes...observe if we take your monitoring data and plot it to see what it looks like ("A picture is worth..." even when collecting images. <vbg>)
s=["Frames captured: 3437, Memory: 3099373568"
"Frames captured: 3482, Memory: 2996944896"
"Frames captured: 3526, Memory: 2891186176"
"Frames captured: 3570, Memory: 2786598912"
"Frames captured: 3615, Memory: 2678345728"
"Frames captured: 3660, Memory: 2572312576"
"Frames captured: 3706, Memory: 2464108544"
"Frames captured: 3752, Memory: 2357243904"
"Frames captured: 3799, Memory: 2248380416"
"Frames captured: 3845, Memory: 2136969216"
"Frames captured: 3892, Memory: 2027577344"
"Frames captured: 3938, Memory: 1915494400"
"Frames captured: 3985, Memory: 1808896000"
"Frames captured: 4002, Memory: 1708388352"];
f=str2double(extractBetween(s,'ed: ',','));
m=str2double(extractAfter(s,'ry: '));
tCapture=table(f,m,'VariableNames',{'Frame','FreeMemory'});
tCapture=addvars(tCapture,[nan;diff(tCapture.Frame)],[nan;-diff(tCapture.FreeMemory)],'NewVariableNames',{'NFrames','MemUsed'});
tCapture.MemPerFrame=tCapture.MemUsed./tCapture.NFrames/1024/1024
yyaxis left
plot(tCapture.Frame,tCapture.FreeMemory/1024^3,'X')
ylabel('Free Memory (GB)')
yyaxis right
plot(tCapture.Frame,tCapture.MemPerFrame,'X')
hAx=gca;
set(hAx.YAxis,{'TickLabelFormat'},{'%0.1f'})
title('Image Capture Memory Useage vs Frame Number')
ylabel('Memory Per Frame(MB)')
xlabel('Frame Number')
We can observe the memory usage is almost perfectly linear with frame number until the very end(*) when the indicated memory usage almost doubled on average. We don't have the data for every image to observe, but one presumes that probably it stayed at the 2MB value until the very last acquired frame and then ran into the allocation problems.
As Bruno, it does seem peculiar that the system still has almost 2GB of overall free memory, but can't seem to find 2MB free; this may indicate some per process limit or other issue with how memory usage is being handled.
(*) Looking at the finer detail, NB the memory per frame is pretty flat until after frame 3800, it then seems more variable for some reason. It's also tantalizing that the first point shown is also lower before the plateau is established after 3500; it would be interesting to observe what the startup transient might look like and if for some reason the application is requiring more memory as it goes along on a per image basis.
We don't know the size/depth of the frame so don't know how this compares to an expected memory footprint.
4 Comments
dpb
on 5 Apr 2023
Edited: dpb
on 5 Apr 2023
No, I don't have access to the IMAQ TB other than by downloading a trial and then don't have any hardware to use it with, anyway, if did.
But, I think it's conclusive that Bruno hit the nail on the head; the TB acquisition logic is dumb; it allocates the entire buffer including room for a new image every frame and copies the old buffer over and adds a new frame at the end.
2.2M/frame * 4K frames is the 8.8G; when try to double that by allocating a new buffer + new frame to copy the old over to, it exceeds the 16G you have available and dies. Pretty damning evidence that it occurs at almost exactly the 4K number.
This is a grievous fault in the TB design/implementation; it should keep a list structure or some similar way to implement a growing buffer and only add the additional memory for the next frame. There will be some other overhead associated with keeping that data structure, so won't be able to allocate all memory to an image buffer, but certainly could use a very significant fraction of total memory. Of course, then one will run into issues trying to process those later on if actually do completely fill memory, but...
Unless there's a way to preset the number of images wanted to be collected and that will make it allocate the total memory to begin with instead of just free-running???
If not, I'd say this is a quality of implementation issue deserving of a bug/issue report to TMW and it would appear the only choices one would have to collect more frames to memory would be to add memory to the system.
Alternatively, could you stream to disk instead? If your disk is a SSD, performance shouldn't be too bad compared to memory.
See Also
Categories
Find more on Startup and Shutdown in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!