Ho il seguente codice, che genererà un OutOfMemoryException
quando viene eseguito:Qual è l'alternativa a GarbageCollector?
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;
}
}
Qualora un Graphics_Canvas
è definito come segue:
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);
}
}
E il codice XAML per creare il Window
è come questo:
<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>
Ora, questo è solo un esempio per illustrare il mio punto, che è in alternativa è qui per utilizzare il Garbage Collector ...
Se si esegue il programma e si continua a spostare il mouse su Graphics_Canvas
, la memoria utilizza build, build e build fino a ottenere uno OutOfMemoryException
. Se si aggiunge GC.Collect()
dove ho commentato, ciò non accade (sebbene la memoria aumenti di una piccola quantità, per ragioni esterne a me e, si spera, sia collegata al mio problema), e il programma continui a funzionare.
Quindi, perché il GC
non avvia e cancella questa memoria e interrompe l'eccezione? Se sto facendo un errore molto fondamentale sarei molto felice che qualcuno me lo indicasse in modo da poter andare oltre.
Ho visto molte volte su questo sito Web e altri consigli dai programmatori che dicono "non usare mai il Garbage Collector". Voglio conformarmi alle migliori pratiche, ma non vedo in situazioni come questa che altro potrei fare.
Per essere completamente onesti; Trovo strano che il sistema lanci un 'OutOfMemoryException' ** prima ** tentando un 'GC.Collect()'. Solo i miei due centesimi. – Nolonar
Attendi, il codice prima * rimuove * un elemento e poi ne aggiunge un altro. Va bene. –
E la parte 'prima cancella i dati del display corrente'? – RichieHindle