2015-05-13 2 views
0

Я использую следующий код. Как я увидел это в профиле профилей .Net, я обнаружил, что утечки памяти происходят.Как освободить память, используемую новым классом, чтобы избежать утечки памяти?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Forms; 
using System.ComponentModel; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 
namespace TestMemLeak 
{ 
public partial class MainWindow : Window 
    { 

    public int count = 0; 
    BackgroundWorker worker = new BackgroundWorker(); 
    public class test 
    { 
     public int sno{get; set;} 
     public string col1 { get; set; } 
     public string col2 { get; set; } 
     public string col3 { get; set; } 
     public string col4 { get; set; } 
     public string col5 { get; set; } 
     public string col6 { get; set; } 
     public string col7 { get; set; } 

    } 
    // test test1 = new test(); 
    public MainWindow() 
    { 
     InitializeComponent(); 
     worker.WorkerReportsProgress = true;   // For Background Worker 
     worker.DoWork += worker_DoWork; 
     worker.ProgressChanged += worker_ProgressChanged; 
     worker.WorkerSupportsCancellation = true; 
     worker.RunWorkerCompleted += worker_RunWorkerCompleted; 
    } 


    private void Load_Click(object sender, RoutedEventArgs e) 
    { 
     dg1.Items.Clear(); 
     worker.RunWorkerAsync(); 
    } 
    void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     // int max = (int)e.Argument; 

     for (int i = 1; ; i++) 
     { 
      (sender as BackgroundWorker).ReportProgress(i); 
      System.Threading.Thread.Sleep(1); 


      if (worker.CancellationPending) 
      { 
       e.Cancel = true; 
       return; 
      } 
     } 
    } 
    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     int i = e.ProgressPercentage; 


     if (i > 100000) 
     { 
      count++; 
      if (count == 100) 
      { 
       for (int k = 0; k < 100; k++) 
       { dg1.Items.RemoveAt(0); } 
       count = 0; 
      } 
     } 

      dg1.Items.Add(new test() {sno=i,col1="test",col2="test",col3="test",col4="test",col5="test",col6="test",col7="test" }); 



    } 

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (e.Cancelled) 
     { 
      System.Windows.MessageBox.Show("Task Cancelled....."); 
     } 

      // Check to see if an error occurred in the background process. 

     else if (e.Error != null) 
     { 
      System.Windows.MessageBox.Show("Error while performing background operation." + e.Error.Message); 
     } 
     else 
     { 
      // Everything completed normally. 
      System.Windows.MessageBox.Show("Task Completed..." + e.Result); 
     } 
    } 

    private void Stop_Click(object sender, RoutedEventArgs e) 
    { 
     worker.CancelAsync(); 

    } 

    private void Clear_Click(object sender, RoutedEventArgs e) 
    { 
     // worker.CancelAsync(); 
     dg1.Items.Clear(); 
     // GC.Collect(); 
    } 
} 
} 

Здесь каждый раз, когда я создаю новый тест класса, так что она занимать память и не освободившись от GC. как я могу избежать этого?

+0

Вы просто добавляете и очищаете элементы в своем DataGrid, и эти операции вызваны утечками памяти? – StepUp

+0

Можете ли вы добавить вывод своего профилировщика памяти, который показывает путь корня GC одного из просочившихся элементов? Кроме того, какова ваша процедура тестирования? Когда вы захватываете снимки? –

+0

Вы получаете OutOfmemoryException, или вы просто смотрите на память, используемую вашим приложением? GC.Collec() t не очищает все неиспользуемые ссылки. Возможно, вам потребуется вызвать GC.Collect (2), поскольку элементы могут считаться долговечными объектами: https://msdn.microsoft.com/en-us/library/ee787088(v=vs.110).aspx – Liero

ответ

0

Я вижу, что вы регистрируете эти события:

worker.DoWork += worker_DoWork; 
worker.ProgressChanged += worker_ProgressChanged; 
worker.RunWorkerCompleted += worker_RunWorkerCompleted; 

Вы должны отменить их в какой-то момент. Для этого вы можете реализовать интерфейс IDisposable в своем классе и отменить регистрацию событий в функции Dispose. Что-то вроде этого:

public partial class MainWindow : Window, IDisposable 
{ 

...

public void Dispose() 
    { 
     worker.DoWork -= worker_DoWork; 
     worker.ProgressChanged -= worker_ProgressChanged; 
     worker.RunWorkerCompleted -= worker_RunWorkerCompleted; 
    } 
} 

И вы можете также установить BackgroundWorker нулевое значение, на всякий случай.

+4

Обработчики событий создают только сильную ссылку на форму в рабочем, а не наоборот. Работник удерживается как поле экземпляра формы, к которой он прикреплен, поэтому там нет утечки. –

+0

Я пытался объявить класс как Idisposable, но я не получил. не могли бы вы изменить мой код в соответствии с этим –

+0

Посмотреть мое сообщение для кода – mgarant

0

Когда вы отказаться от подписки на события

Обычно это требуется, чтобы отказаться от подписки на события, если они принадлежащих к другому классу или, если издатель живет дольше, чем абонент. Здесь backgroundWorker - это ваша переменная класса, а ее продолжительность жизни равна времени жизни экземпляра этого класса. Таким образом, не нужно отказываться от этих обработчиков событий.

Когда реализовать IDisposable

Вы должны осуществлять IDisposable pattern, если у вас есть какие-либо переменные класса, которые реализованы интерфейс IDispose. Просто, если у вас есть какие-либо переменные класса, у которых есть метод Dispose, вы должны реализовать интерфейс IDispose и Dispose для всех одноразовых объектов.

в вашем коде

Видимо у вас есть какие-то одноразовые предметы (объекты имеют те Утилизировать методы) в вашем представлении. (по крайней мере, DataGrid является одноразовым, я думаю) Внедрите интерфейс IDisposable и удалите все одноразовые объекты.

Убедитесь, что вы вызвали метод Dispose, соответствующий после реализации шаблона IDisposable! Просто реализация этого не имеет никакого эффекта.

+0

«Как правило, вы должны отказаться от подписки на события, только если подписались на издателя, который живет дольше, чем ваш абонент». Я не согласен с этим утверждением. Во-первых, я считаю, что это неправильно, (издатель ссылается на подписчика, сохраняя его). Во-вторых, CAN и СЛЕДУЮТ очень разные концепции, https://www.ietf.org/rfc/rfc2119.txt. Несмотря на то, что код отмены подписки не нужен, как правило, это невозможно понять, если быстро взглянуть на исходный код. – Aron

+0

@ Арон: Что ж, я передумал, я выражаю это. Спасибо за ваш комментарий. Что касается издателя и подписчика, это именно то, что я хочу сказать. Издатель живет дольше и держит ссылку на подписчика. Таким образом, GC не может собирать Абонента, даже если он расположен. – CharithJ

Смежные вопросы