我有增加内存的问题。我有一个来自相机的图像。图像由具有非托管代码的函数处理。如果找不到预期的模式,则此功能需要很长时间(几秒钟)。如果可以找到模式,则返回结果非常快(几毫秒)。
我尝试在200分钟后在新的Thread
和Abort
中开始后处理。到目前为止这个工作。现在我有了问题,我的记忆力增长了。也许using
子句没有按预期工作,图像保存在内存中......
private void ImageWorker()
{
while (_imageWorkerRunning)
{
try
{
using (var img = CameraHelper.GetImage())
{
var waiter = new ManualResetEvent(false);
ProcessResult result = null;
var thd = new Thread(() => {
result = UnManagedImageProcessor.Process(img);
waiter.Set();
});
thd.Start();
waiter.WaitOne(200);
if (thd.ThreadState == ThreadState.Running || result == null)
{
thd.Abort();
while (thd.ThreadState != ThreadState.Aborted) new ManualResetEvent(false).WaitOne(10);
}
Application.Current.Dispatcher.Invoke(() => DisplayImage = img);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}
GC
在中止的线程上是否正常工作?我想也许这是我的问题...
Solutiuon:
我将代码更改为以下内容。现在我有两个并行任务。第一个是获取图像和检查,如果处理可用。
如果是,则将图像提供给此ImageProcessing
任务。这仅在Success
上显示图像(然后处理速度很快,每张图片都可以处理)。
如果处理不成功,则需要一些时间,图像仅显示为实时图像(ImageWorker
)。
private readonly object _imageLock = new object();
private ExtendedImage _sharedProcessingImage;
private readonly ManualResetEvent _processingWaiter = new ManualResetEvent(false);
private bool _processingWaits = false;
private void ImageWorker()
{
while (_imageWorkerRunning) {
try {
var img = CameraHelper.GetImage();
if (_processingWaits) {
//processing available --> process image
lock (_imageLock) {
_sharedProcessingImage = img;
}
_processingWaits = false;
_processingWaiter.Set();
}
else {
//Processing in progress --> Only display image
Application.Current.Dispatcher.Invoke(() => DisplayImage = img);
}
new ManualResetEvent(false).WaitOne(50);
}
catch (Exception e) {
_log.Error(e);
}
}
}
private void ImageProcessing()
{
while (_imageWorkerRunning) {
_processingWaits = true;
_processingWaiter.WaitOne();
_processingWaiter.Reset();
lock (_imageLock) {
try {
result = UnManagedImageProcessor.Process(_sharedProcessingImage);
// ... handle result
if(result.Succeeded) Application.Current.Dispatcher.Invoke(() => DisplayImage = _sharedProcessingImage);
}
catch (Exception e) {
_log.Error(e);
}
}
}
}
感谢您的帮助。
答案 0 :(得分:2)
我建议您使用BlockingCollection。
要显示图像,您可以使用储物柜,每次UI处于空闲状态时,您都可以锁定对象,获取最后一张图像并处理前一张图像。此外,每次处理图像时,您都要锁定对象并将var设置为最后一个。
显示逻辑:
readonly object lastProcessdImageLocker = new object();
Bitmap lastProcessdImage;
//Every time a image process is done:
lock(lastProcessdImageLocker)
lastProcessdImage = imageJustProcessed;
//Every time the UI thread is idle
lock(lastProcessdImageLocker)
myPictureboxImage = lastProcessdImage;
//Here you should also dispose the previus myPictureboxImage so you prevent your memory usage to grow fast!
See this post for more info about WPF and also WinForm render loop
使用BlockingCollection消耗(处理)相机图像的示例代码:
BlockingCollection<Bitmap> cameraImages = new BlockingCollection<Bitmap>();
//使用另一个theard来填充cameraImages,就像这样: //cameraImages.Add(CameraHelper.GetImage());
void StartProcess()
{
if (processImageThread== null || !processImageThread.IsAlive)
{
processImageThread= new Thread(ProcessLoop);
processImageThread.Name = "ProcessLoop";
processImageThread.IsBackground = true;
processImageThread.Start();
Console.TraceInformation("ProcessLoop started");
}
}
private void ProcessLoop()
{
try
{
foreach (img in cameraImages.GetConsumingEnumerable(CancelProcessing.Token))
{
// Do your stuff
}
}
catch (OperationCanceledException)
{
Console.WriteLine("ProcessLoop OperationCanceledException.");
}
finally
{
}
}
如果您的cameraImages计数增长太快(内存不足),则需要缩短处理时间或停止相机一段时间。