好的GC.Collect

时间:2015-04-08 18:25:52

标签: c# multithreading image-processing garbage-collection

我知道有很多关于这方面的话题,这通常是一个坏主意,但这是一个相对具体的案例。除了GC.Collect之外,我唯一能够解决问题的方法是“减慢”应用程序,或者使用更少的线程。我已经复制了我的应用程序实际执行的一小部分内容,因此我可以在本地重新创建该问题。以下代码非常快速地获得$ OutOfMemoryException。 *注意我没有包含它获取byte [] i1的部分,但它非常通用。

private static byte[] i1;
private static  IList<Guid> jobs;
static void Main(string[] args)
    {

        jobs = new List<Guid>();
        StartThreads(5);
        Console.ReadLine();

    }

 public static void StartThreads(int maxThreads)
    {
        while (true)
        {
            tcount ++;
            if (jobs.Count >= maxThreads) continue;
            ThreadStart ts = (ProcessImage);

            var workerThread = new Thread(ts) { IsBackground = true };
            workerThread.Start();
        }
    }

public static void ProcessImage()
    {
        var guid = Guid.NewGuid();
        try
        {
            lock (jobs)
            {
                jobs.Add(guid);
            }

            var x = ByteArrayToImage(i1);
            var y = ByteArrayToImage(i1);
            OverlayImages(x, y);
        }
        catch (Exception e)
        {

            Console.WriteLine(e.StackTrace);
        }
        finally
        {
            lock (jobs)
            {
                jobs.Remove(guid);
            }
           // GC.Collect();
        }
    }


 private static void OverlayImages(Image ymcImage, Image kImage)
    {
        var attr = new ImageAttributes();
        attr.SetColorKey(Color.White, Color.White);
        Graphics g = Graphics.FromImage(ymcImage);
            var destRect = new Rectangle(0, 0, ymcImage.Width, ymcImage.Height);
            var templateBmp = new Bitmap(kImage);
            g.DrawImage(templateBmp, destRect, 0, 0, kImage.Width, kImage.Height, GraphicsUnit.Pixel, attr);
        g.Dispose();
    }

  public static Image ByteArrayToImage(byte[] image)
    { 
        using (MemoryStream ms = new MemoryStream(image))
        {

           return Image.FromStream(ms);
        }
    }

如果我将最大线程数减少到5,我可以看到(通过观察任务管理器中的进程)内存增加,大约每9个“滴答”(当任务管理器更新时,每个大约1秒)或者它)它回收了大部分。在5或更高的情况下,内存似乎在前9个“滴答”之前达到致命级别(大约1.6G)并且崩溃。在4个线程中,我可以看到内存增加到1G以上,然后回到大约70M,并重复。线程越少,收集前的时间就越少。如果我取消注释GC.Collect,我可以运行20个线程,内存保持在100到200之间。

我也一直在玩ByteArrayToImage中的各种事情来尝试不使用这么多内存,但我已经在这方面取得了真正的成功。这包括克隆图像并将其返回到使用之外并删除using语句

此外,我的应用程序无法快速完成,并且很难确切地说出发生了什么。我无法在测试环境中重现完整应用程序中的重负载。但它每天都会得到一次OutOfMemoryException。它将连续几次并自行恢复,但在此过程中会丢失一些工作。我不确定这是否能解决我的问题,但这是我在测试中遇到的问题。我想我只是想知道其他有更多专业知识的人会想到这个,如果有更好的选择,而不是自己调用GC。

0 个答案:

没有答案