我有以下代码,运行时会生成OutOfMemoryException
:
public partial class MainWindow : Window
{
private DrawingVisual myVisual = new DrawingVisual();
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
myVisual = GetVisual();
graphicsCanvas.AddVisual(myVisual);
}
private void Graphics_Canvas_MouseMove(object sender, MouseEventArgs e)
{
//get the data visual:
DrawingVisual tempVisual = GetVisual();
//first clear the current display data:
graphicsCanvas.RemoveVisual(myVisual);
//get the data visual:
myVisual = tempVisual;
graphicsCanvas.AddVisual(myVisual);
//GC.Collect();
}
private DrawingVisual GetVisual()
{
double width = graphicsCanvas.ActualWidth;
double height = graphicsCanvas.ActualHeight;
DrawingVisual dV = new DrawingVisual();
Rect clipRect = new Rect(0, 0, width, height);
dV.Clip = new RectangleGeometry(clipRect);
using (DrawingContext dC = dV.RenderOpen())
{
RenderTargetBitmap rTB = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
if (rTB.CanFreeze)
{
rTB.Freeze();
}
dC.DrawImage(rTB, clipRect);
}
return dV;
}
}
Graphics_Canvas
的定义如下:
class Graphics_Canvas : Canvas
{
private List<DrawingVisual> visuals = new List<DrawingVisual>();
protected override int VisualChildrenCount
{
get { return visuals.Count; }
}
protected override Visual GetVisualChild(int index)
{
return visuals[index];
}
public void AddVisual(DrawingVisual visual)
{
visuals.Add(visual);
base.AddVisualChild(visual);
base.AddLogicalChild(visual);
}
public bool ContainsVisual(DrawingVisual visual)
{
return visuals.Contains(visual);
}
public bool HasVisuals
{
get { return visuals.Count > 0; }
}
public void RemoveAllVisuals()
{
for (int i = 0; i < visuals.Count; i++)
{
RemoveFromLogicalTree(visuals[i]);
}
visuals.Clear();
}
private void RemoveFromLogicalTree(Visual visual)
{
RemoveLogicalChild(visual);
RemoveVisualChild(visual);
}
public void RemoveLastVisual()
{
if (visuals.Count > 0)
{
int index = visuals.Count - 1;
RemoveFromLogicalTree(visuals[index]);
visuals.Remove(visuals[index]);
}
}
public void RemoveVisual(DrawingVisual visual)
{
RemoveFromLogicalTree(visual);
visuals.Remove(visual);
}
}
创建Window
的XAML是这样的:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:csMemoryLeakTestProject" x:Class="csMemoryLeakTestProject.MainWindow"
Title="MainWindow"
Background="Gray"
Height="600" Width="800"
WindowStartupLocation="CenterScreen"
Loaded="Window_Loaded">
<Grid>
<local:Graphics_Canvas Margin="12" Background="White" x:Name="graphicsCanvas" MouseMove="Graphics_Canvas_MouseMove"/>
</Grid>
</Window>
现在,这只是一个例子来说明我的观点,即我不明白使用垃圾收集器的替代方案是什么......
如果您运行程序,并继续将鼠标移到Graphics_Canvas
上,则内存使用构建,构建和构建,直到获得OutOfMemoryException
。如果你在GC.Collect()
添加我已经评论过的地方,这种情况就不会发生(尽管内存确实增加了一小部分,原因超出了我,并希望与我的问题相关联),并且程序继续发挥作用。
那么,为什么GC
没有启动并清除此内存并停止发生异常?如果我正在做一些非常根本性的错误,我会非常高兴有人向我指出,以便我可以超越这个。
我在这个网站上看到过很多次以及其他程序员的建议,他们说“从不使用垃圾收集器”。我想要遵循最佳实践,但我不会在这样的情况下看到我还能做什么。
答案 0 :(得分:9)
程序无法管理大量内存,这不是GC
的错误。
在您的计划中,您可以:
private void Graphics_Canvas_MouseMove(object sender, MouseEventArgs e)
{
....
//ADD ELEMENTS ON EVERY MOVE !
graphicsCanvas.AddVisual(myVisual);
//GC.Collect();
}
Tou为每个鼠标移动添加一个元素,因此增加集合大小。你会期待什么?
因此,在 90%的情况下,针对这类问题的解决方案是重新架构您的代码。
示例:
每次将新元素添加到chidren视觉集合时,几乎不可能在MouseMove上添加。可能是重用已经存在的情况。
GC
的明确使用并非建议,但有时我们需要使用它。但是,我再说一遍,我很难相信,在这种情况下你需要以这种方式管理程序。
答案 1 :(得分:-1)