【问题标题】:C# object array = null, doesn't free memoryC# object array = null,不释放内存
【发布时间】:2013-01-08 09:00:22
【问题描述】:

在我做的项目中出现了内存泄漏。我重写了所有的函数来修复一些,但还剩下一个:

该程序有一个面板对象数组,每次我放入一个新面板时,它都会增长。当它达到 400 个面板时,它会删除最旧的面板以释放一些内存。

我不明白的是:

tempPanels = new Panel[panels.Length];
Array.Copy(panels, 1, tempPanels, 0, panels.Length - 1);//delete the oldest history log (the first of the array)
panels = null; //empty object array
panels = new Panel[tempPanels.Length + 1]; //set new length
tempPanels.CopyTo(panels, 0);//restore panels

当我使用上面的代码时,内存使用量仍在不断增加......有人可以解释为什么我必须在将面板设置为空之前先处理面板吗?

tempPanels = new Panel[panels.Length];
Array.Copy(panels, 1, tempPanels, 0, panels.Length - 1);//delete the oldest history log (the first of the array)
panels[0].Dispose();
panels = null; //empty object array
panels = new Panel[tempPanels.Length + 1]; //set new length
tempPanels.CopyTo(panels, 0);//restore panels

提前致谢!

编辑@史蒂夫 B:
该程序制作了一个新面板:panel currentPanel;
当有一个新面板时,我声明 currentPanel:currentPanel = new Panel();
之后我调用这个函数:setCurrentPanelConfiguration:

public void setCurrentPanel()
{
  currentPanel.Name = "panel" + panels.Length;
  currentPanel.Size = new System.Drawing.Size(485, 75);
  currentPanel.BackColor = Color.Transparent;
}

为了修复滚动错误,我使用了一个 Panel HistoryPanel 我将 currentPanel 放在了其中:

HistoryPanel.Controls.Add(currentPanel);

然后我添加所有控件:用户名、当前时间和头像。

为了保存面板,我在创建空间后将其添加到阵列面板中,如上所示:
panels[panels.Length-1] = currentPanel;

我使用数组是因为历史记录显示最新的数组。每次我必须将所有面板向下移动 80 像素时都要这样做。

【问题讨论】:

  • 可以使用垃圾回收器来释放内存:GC.GetTotalMemory(true)
  • 如果我没记错的话,你必须先在面板上调用 dispose。否则,它们将不会被释放。
  • 如果我使用 de 垃圾收集器,我必须将它放在代码中的什么位置,并让我为数组创建析构函数或其他东西?
  • 手动调用垃圾收集器不是个坏主意吗?垃圾收集器不应该检测可释放对象本身并在程序空闲时收集它吗?
  • AFAIK 垃圾收集器不应该永远被显式调用,除非你知道它需要被调用(处理非托管资源?)。仅供参考,如果您将panels 设为一个集合(即List<>),它将非常适合您的代码:panels.RemoveAt(0);,您就完成了。

标签: c# memory


【解决方案1】:

因为将某些内容设置为 null 不会处理它,它只是取消引用它 - 垃圾收集器不会监视您的分配以检查您的 null 引用,它会在需要时执行它(其他所有条件都相同) ) 或当明确告知这样做时。

简而言之,因为null 和内存管理是不同的东西。

【讨论】:

  • 想象一下你有一个盒子,你只是取出里面的东西。盒子还在。这就是你在做什么。删除整个节点。
【解决方案2】:

除了Grant Thomas说的,你为什么不用List<Panel>,这样更容易管理?

代码如下所示(假设 panels 被声明为 List<Panel>):

Panel p = panels[0];
panels.RemoveAt(0);  // This removes the first element

p.Dispose(); // This disposes of the element

如果你想保留你的代码,它应该是这样的:

tempPanels = new Panel[panels.Length];
Array.Copy(panels, 1, tempPanels, 0, panels.Length - 1);//delete the oldest history log (the first of the array)

// Dispose of every element in the array
for (int i = 0; i < panels.Length; i++)
    panels[i].Dispose();

// The following line is unneccessary, as the variable is re-assigned anyway
// panels = null; //empty object array

panels = new Panel[tempPanels.Length + 1]; //set new length
tempPanels.CopyTo(panels, 0);//restore panels

【讨论】:

  • 你是对的!我一直在寻找一个 List,因为我习惯于使用 Java,但它根本不想工作,所以我提出了这个解决方案并且工作正常。变量面板声明为普通数组。
猜你喜欢
  • 2016-10-08
  • 2012-07-08
  • 1970-01-01
  • 1970-01-01
  • 2011-09-13
  • 2017-06-29
  • 2020-09-10
  • 2011-12-27
  • 2014-09-20
相关资源
最近更新 更多