2014-01-12 2 views
3

Grid 컨트롤 imageGrid 및 버튼 buttonRefresh이있는 WPF 창이 있습니다. 이 코드는 테스트 용이며 약간 이상하게 보일 수 있습니다. 창 코드 :그리드 정리 코드

public partial class MainWindow : Window 
{ 
    const int gridWidth = 10; 
    const int gridHeight = 20; 
    const int cellWidth = 100; 
    const int cellHeight = 100; 
    const int bitmapWidth = 1024; 
    const int bitmapHeight = 1024; 
    WriteableBitmap[,] bitmaps; 

    public MainWindow() 
    { 
     InitializeComponent(); 
     buttonRefresh.Click += new RoutedEventHandler(buttonRefresh_Click); 
     FillGrid(); 
    } 

    void buttonRefresh_Click(object sender, RoutedEventArgs e) 
    { 
     FillGrid(); 
    } 

    void FillGrid() 
    { 
     ClearGrid(); 
     CreateBitmaps(); 
     InitGrid(); 
    } 

    void ClearGrid() 
    { 
     imageGrid.Children.Clear(); 
     imageGrid.RowDefinitions.Clear(); 
     imageGrid.ColumnDefinitions.Clear(); 
     bitmaps = null; 
    } 

    void InitGrid() 
    { 
     for (int i = 0; i < gridWidth; ++i) 
     { 
      ColumnDefinition coldef = new ColumnDefinition(); 
      coldef.Width = GridLength.Auto; 
      imageGrid.ColumnDefinitions.Add(coldef); 
     } 

     for (int i = 0; i < gridHeight; ++i) 
     { 
      RowDefinition rowdef = new RowDefinition(); 
      rowdef.Height = GridLength.Auto; 
      imageGrid.RowDefinitions.Add(rowdef); 
     } 

     for (int y = 0; y < gridHeight; ++y) 
     { 
      for (int x = 0; x < gridWidth; ++x) 
      { 
       Image image = new Image(); 
       image.Width = cellWidth; 
       image.Height = cellHeight; 
       image.Margin = new System.Windows.Thickness(2); 
       image.Source = bitmaps[y, x]; 

       imageGrid.Children.Add(image); 
       Grid.SetRow(image, y); 
       Grid.SetColumn(image, x); 
      } 
     } 
    } 

    void CreateBitmaps() 
    { 
     bitmaps = new WriteableBitmap[gridHeight, gridWidth]; 

     byte[] pixels = new byte[bitmapWidth * bitmapHeight]; 
     Int32Rect rect = new Int32Rect(0, 0, bitmapWidth, bitmapHeight); 

     for (int y = 0; y < gridHeight; ++y) 
     { 
      for (int x = 0; x < gridWidth; ++x) 
      { 
       bitmaps[y, x] = new WriteableBitmap(bitmapWidth, bitmapHeight, 96, 96, PixelFormats.Gray8, null); 

       byte b = (byte)((10 * (x + 1) * (y + 1)) % 256); 

       for (int n = 0; n < bitmapWidth * bitmapHeight; ++n) 
       { 
        pixels[n] = b; 
       } 

       bitmaps[y, x].WritePixels(rect, pixels, bitmapWidth, 0); 
      } 
     } 
    } 
} 

이 프로그램을 시작하면 FillGrid 함수가 성공적으로 실행됩니다. 새로 고침 버튼을 클릭하면 FillGrid이 다시 실행되고 이번에는 new WriteableBitmap 라인이 OutOfMemoryException을 던졌습니다. 나는 ClearGrid 함수가 모든 리소스를 해제하지 않으며, bitmaps 배열이 아직 파괴되지 않았다고 생각합니다. 이 코드의 문제점은 무엇입니까?

XAML은 : 귀하의 경우 WriteableBitmap에서 메모리 누수를 만들기 때문에

<Window x:Class="Client.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Grid and DirectX" Height="600" Width="800"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="*"/> 
     </Grid.RowDefinitions> 

     <Button HorizontalAlignment="Center" Padding="20 2" Margin="0 2" Name="buttonRefresh"> 
      Refresh 
     </Button> 

     <ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto"> 
      <Grid Name="imageGrid"/> 
     </ScrollViewer> 
    </Grid> 
</Window> 

답변

1

이것은 WPF에서 오래된 문제입니다이다. here 조언으로

using System.Windows.Interop; 

public RenderMode RenderMode { get; set; } 

RenderMode = RenderMode.SoftwareOnly; 

을하지만, 도움이되지 않았다 : 내 컴퓨터에서 프로그램이 메모리의 기가 바이트 소요, 나는 SoftwareOnlyRenderMode에 설치하려고. 당신의 ClearGrid() 방법

GC.Collect(); 

을하지만, 도움이되지 않았다 : 또한 GarbageCollector 전화를 강제로 시도.

당신은 여기에 게시 된 솔루션을 보려고해야합니다

Silverlight's Big Image Problem (and What You Can Do About It)

WPF BitmapImage Memory Leak

Why GC.Collect() doesn't help?

이 주제는 매우 광범위하다, 그러나 나는 시도 할 것이다 그 이유를 간략히 설명하기. 대부분의 경우 개발자는 가비지 컬렉터를 수동으로 호출하면 안됩니다. 콜렉터가 꽤 지능적이며 지속적으로 실행되기 때문에 힙 메모리에서 객체를 정리할 수 있다면 그는 수행했을 것입니다. 매우 드물고 독점적 인 상황에서만 수동으로 호출해야하며 여러 성능 테스트를 수행해야합니다. 나는 또한이 답변 (Best Practice for Forcing Garbage Collection in C#)에서 인용하려면 : 닷넷 GC가 잘 설계 및 튜닝

적응 될, 그것은의 "습관"에 따라 GC0/2분의 1 임계 값을 조정할 수 있음을 의미하여 프로그램 메모리 사용. 따라서 시간이 지나면 프로그램에 적용됩니다. GC.Collect를 명시 적으로 호출하면 임계 값이 재설정됩니다! .NET은 프로그램의 "습관"에 다시 적응할 시간을 보냈습니다.

WPF RenderTargetBitmap still leaking, and badly

가비지 수집기 발생 개체 (gen1에이어서, gen0에서 제) 서서히 넣는다 번째 세대 :

WriteableBitmap 그 하나의 예, 수정 될 수없는 버그가 gen2, 그리고 그가 거기에 "살아"있다고 믿기 때문에 남아있다.gen2에서 세대는 일반적으로 몇 가지 경우에, 매우 드물게 청소되지 않은 :

  • 시스템은 낮은 물리적 메모리가 있습니다.

  • 관리되는 힙의 할당 된 개체가 사용하는 메모리가 허용되는 임계 값을 초과합니다. 이 임계 값은 프로세스가 실행될 때 지속적으로 조정됩니다. 버그의 경우 쓰레기로 쓰레 쉬 홀드를 늘릴 수 있습니다.

  • GC.Collect 메서드가 호출됩니다. 대부분의 경우 가비지 컬렉터가 계속 실행되기 때문에이 메서드를 호출 할 필요가 없습니다. 이 방법은 주로 고유 한 상황 및 테스트에 사용됩니다.

+0

@Alex Farber : 제 질문에 대한 편집 - 왜 GC.Collect()가 도움이되지 않습니까? '를 참조하십시오. –