后台工作人员体内的新位图导致内存泄漏

时间:2019-03-19 22:31:40

标签: c# memory-leaks

我正在绘制可视化的WaveIn记录数据,仅用于测试目的,以查看数据的正确性。 如您所见,我的机制是:

1)一些WaveIn线程(不包括在内)通过带有音频缓冲区的委托戳此Form。

2)背景工作者获取更新的音频数据,绘制位图 完成后,它会报告进度,并且该本地表单线程中的句柄只需调用WM_PAINT即可用新图片更新PictureBox背景。

object localLock = new object();
Bitmap soundGraphImage;

private void soundGrapher_DoWork(object sender, DoWorkEventArgs e) {
    while(are.WaitOne())
    {
        if (soundGrapher.CancellationPending) {
            e.Cancel = true;
            return;
        }
        if (audioData == null || audioData.Length == 0) continue;
        soundGraphImage = new Bitmap(graphWidth, graphHeight); <----- this one
        Graphics g = Graphics.FromImage(soundGraphImage);
        lock (localLock)
        {
            #region Draw sound
            if (audioParms.nChannels > 1) { Vfw_MessageOut("More than 1 channel"); return; }
            int currentPos = 1;
            int accu = 0;
            int x = 1;
            int maxValue = 0;
            int baseY = soundGraph.Height / 2;

            int bytes = audioParms.wBitsPerSample / 8;
            int portion = (int)Math.Round(1.0 * audioData.Length / bytes / soundGraph.Width, MidpointRounding.ToEven);
            switch (bytes)
            {
                case 1: maxValue = Byte.MaxValue; break;
                case 2: maxValue = Int16.MaxValue; break;
                case 4: maxValue = Int32.MaxValue; break;
            }

            int halfValue = maxValue / 2;
            double coeff = multiPlyer * baseY / halfValue;
            for (int i = 0; i < audioData.Length; i = i + bytes)
            {
                if (currentPos == portion)
                {
                    accu = (int)(accu / portion);
                    g.DrawLine(Pens.White, new Point(x, baseY),
                        new Point(x, baseY - (int)(coeff * accu)));
                    currentPos = 1;
                    i = i - bytes;
                    x++;
                }
                else
                {
                    currentPos++;
                    switch (bytes)
                    {
                        case 1: accu += audioData[i] - halfValue; break;
                        case 2: accu += BitConverter.ToInt16(audioData, i); break;
                        case 4: accu += BitConverter.ToInt32(audioData, i); break;
                    }
                }
            }
            #endregion
        }
            g.Dispose();
            soundGrapher.ReportProgress(0);
    }
}
private void soundGrapher_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {

}
private void soundGrapher_ProgressChanged(object sender, ProgressChangedEventArgs e) {
    soundGraph.Invalidate();
}

问题出在位图中。此代码导致内存泄漏。 请帮我避免这个问题。

更新

  

是的,解决方案很简单,只需对其进行处置即可。   当然,靠我自己,但是我仍然有一个更大的问题,这   当位图进入阶段时,位图就在我的栈顶   “堆栈溢出”。但是无论如何这是GC的错。   控制这样的事情。回调每秒仅戳一次。   以前从未在每个位图上调用Dispose   项目。

1 个答案:

答案 0 :(得分:1)

更新

  

“使用”将破坏位图,但我仍然需要它   抽奖。

哦,亲爱的...

在每次重新创建它时,您仍然都必须Dispose进行一些操作……

我可以建议

soundGraphImage?.Dispose();
soundGraphImage = new Bitmap(graphWidth, graphHeight);

原始

在任何可以支持它的东西上都使用using语句,遵守该规则,并且(在这种情况下)您可能是对的。

在这方面,您至少应该在以下方面实现using:-

using(var soundGraphImage = new Bitmap(graphWidth, graphHeight))
{
}

在其他对象上,例如Graphics只是为了保持一致


其他资源

using statement (C# Reference)

  

提供了一种方便的语法,可确保正确使用   可分配对象。

The using statement

  

using语句获取一个或多个资源,执行一个   语句,然后处置资源。

IDisposable Interface

  

提供了一种释放非托管资源的机制。