2013-03-25 36 views
7

Tôi đã đoạn mã sau, mà sẽ tạo ra một OutOfMemoryException khi chạy:Thay thế cho GarbageCollector là gì?

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; 
    } 
} 

Trường hợp Graphics_Canvas được định nghĩa như sau:

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);    
    } 
} 

Và XAML để tạo ra các Window là như thế này:

<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> 

Bây giờ, đây chỉ là ví dụ minh họa quan điểm của tôi, đó là tôi không hiểu theo cách khác là sử dụng Garbage Collector ...

Nếu bạn chạy chương trình và tiếp tục di chuyển chuột qua Graphics_Canvas, việc sử dụng bộ nhớ sẽ tạo và xây dựng và xây dựng cho đến khi bạn nhận được OutOfMemoryException. Nếu bạn thêm vào GC.Collect() nơi tôi đã nhận xét nó, điều này không xảy ra (mặc dù bộ nhớ tăng lên một lượng nhỏ, vì những lý do ngoài tôi và hy vọng liên kết với vấn đề của tôi) và chương trình tiếp tục hoạt động.

Vì vậy, tại sao GC không khởi động và xóa bộ nhớ này và dừng ngoại lệ xảy ra? Nếu tôi đang làm một số lỗi rất cơ bản, tôi sẽ rất vui vì một người nào đó đã chỉ ra cho tôi để tôi có thể vượt qua điều này.

Tôi đã thấy nhiều lần trên trang web này và những lời khuyên khác từ các lập trình viên nói rằng "không bao giờ sử dụng Bộ sưu tập rác". Tôi muốn phù hợp với thực hành tốt nhất, nhưng tôi không thấy trong những tình huống như thế này những gì khác tôi có thể làm.

Trả lời

9

Nó không phải là lỗi của GC rằng chương trình không thể quản lý nhiều bộ nhớ. Trong chương trình của bạn, bạn thực hiện:

private void Graphics_Canvas_MouseMove(object sender, MouseEventArgs e) 
{ 
    .... 
    //ADD ELEMENTS ON EVERY MOVE ! 
    graphicsCanvas.AddVisual(myVisual); 

    //GC.Collect(); 
} 

Tou thêm phần tử vào mỗi lần di chuyển chuột, vì vậy hãy tăng kích thước bộ sưu tập. Những gì bạn mong đợi sẽ xảy ra?

Vì vậy, trong 90% trường hợp, giải pháp cho các loại sự cố này, là rearchitect mã của bạn.

Ví dụ:

Đó là hầu như không thể là bạn cần trên MouseMove thêm mỗi lần một yếu tố mới để một bộ sưu tập trẻ em thất của thị giác. Có thể đó là một trường hợp để tái sử dụng đã trình bày một.

Sử dụng ngầm GC không phải là được đề xuất, nhưng đôi khi chúng tôi cần sử dụng nó. Nhưng, tôi lặp lại, tôi khó có thể tin rằng trong trường hợp này bạn cần quản lý chương trình theo cách đó.

+2

Hoàn toàn trung thực; Tôi thấy nó kỳ lạ, rằng hệ thống sẽ ném một 'OutOfMemoryException' ** trước khi thử một' GC.Collect() '. Chỉ cần hai xu của tôi. – Nolonar

+3

Đợi, mã trước tiên là * xóa * một phần tử rồi thêm một phần tử khác. Đó là tốt. –

+1

Điều gì về phần đầu tiên xóa dữ liệu hiển thị hiện tại? – RichieHindle

-1

Tôi nghĩ điều này mô tả những gì có thể giữ cho các đối tượng của bạn còn sống;

http://msdn.microsoft.com/en-us/library/bb613565.aspx

Tóm lại; các tham chiếu trong trình xử lý sự kiện vẫn có thể tồn tại.

+1

Nếu đó là vấn đề, gọi 'GC.Collect()' sẽ không sửa chữa nó. – RichieHindle

+0

@IvoTops Có, tôi đã đọc về điều này. Tuy nhiên, mã được đăng ở trên là toàn bộ mã cho chương trình này và tôi đã không thêm sự kiện nào, vì vậy tôi không chắc liệu đây có phải là nguyên nhân hay không. Nếu Canvas tự thêm các sự kiện vào hậu trường, tôi có thể làm gì khác để xóa chúng? – Greg

Các vấn đề liên quan