Как освободить занятую память - PullRequest
3 голосов
/ 04 марта 2011

У меня есть главное окно в моем проекте и множество других дочерних вдов внутри главного.
Я заметил это.Когда я открываю главное окно занимает 1500К памяти, при открытии одно дочернее окно затем добавляет в занятую память 6000К.
Когда я открываю второе окно, делаю то же самое.Когда я закрываю два дочерних окна, занятая память не освобождается.
Итак, я хочу освободить занятую память при закрытии дочерних окон.
Как я могу это сделать?
Пожалуйста, посоветуйте мнепример кода на vb.net, если это возможно.
Эта проблема часто возникает в компьютерах локальной сети, а не на моем компьютере (компьютере разработчика, на котором установлен сервер SQL).

Ответы [ 7 ]

13 голосов
/ 04 марта 2011

Некоторые из других ответов на этот вопрос содержат неутешительное количество дезинформации, в то время как другие значительно усложняют проблему. Существует множество заблуждений относительно сборки мусора в .NET, и рассмотренные здесь теории, безусловно, не помогают решить проблему.

Прежде всего, профилирование использования памяти с помощью диспетчера задач Windows - огромная ошибка . Вы серьезно получите неверную информацию , и попытка изменить ваше приложение в соответствии с этой информацией только ухудшит ситуацию, а не улучшит ее. Если вы подозреваете, что у вас есть проблемы с производительностью (и очень сомнительно, что большинство приложений на самом деле будут иметь какие-либо проблемы), вам нужно инвестировать в надлежащий профилировщик памяти и использовать его вместо этого.

Во-вторых, весь смысл сборки мусора в том, что вам не нужно беспокоиться о подобных вещах . И вы не только не должны беспокоиться об этом, но вы также не должны беспокоиться об этом. Вы не должны делать или пытаться каким-либо образом управлять памятью вручную, когда пишете приложения для .NET Framework. Не поддавайтесь искушению возиться с внутренней работой сборщика мусора и крепко прижать пальцы к ушам, когда кто-нибудь скажет вам вызвать GC.Collect вручную, чтобы вызвать сборку мусора. Полагаю, я не должен говорить никогда, но вряд ли есть причина 1017 *. У меня гораздо больше шансов быть подозреваемым кода, который вручную вызывает сборку мусора, чем что-либо еще.

Почему бы вам не запускать сборку мусора вручную? Что ж, помимо очевидного аргумента о том, что он в первую очередь лишает смысла использование управляемого языка, это связано с тем, что сборка мусора является чрезвычайно медленным и дорогостоящим процессом . Вы хотите, чтобы он работал как редко , насколько это возможно, для поддержания максимальной производительности. К счастью, программисты, которые реализовали алгоритмы сборки мусора, намного умнее и опытнее, чем вы или я: они разработали его для запуска только при необходимости , и не чаще этого. Вы не увидите преимущества более частого запуска, но вы увидите недостаток. Это должно быть совершенно непрозрачно для вас, как для программиста.

Единственное исключение - это когда вы работаете с неуправляемыми объектами, которые не собираются или управляются сборщиком мусора. Вы сможете распознать эти объекты, поскольку все они реализуют интерфейс IDisposable , который предоставляет метод Dispose для освобождения неуправляемых ресурсов. На объектах, которые предоставляют этот метод, вы должны вызывать его, как только вы закончите использовать объект. Или, что еще лучше, оберните объявление и использование объекта в using оператор , который автоматически будет обрабатывать удаление объекта, независимо от того, что произойдет ( даже если в коде, где вы используете объект, например, возникает исключение).

Конечно, вы заметите, что несколько стандартных объектов в библиотеке Windows Forms реализуют метод IDisposable. Например, вездесущий Form класс предоставляет метод Dispose. Однако это не обязательно означает, что вы несете ответственность за утилизацию этих предметов вручную. В общем, вам нужно только явно вызвать метод Dispose для объектов, которые вы явно создаете - легко запомнить, верно? Объекты, созданные автоматически Framework, также автоматически уничтожаются Framework. Например, элементы управления, которые вы помещаете на объект Form во время разработки, автоматически удаляются при размещении их формы контейнера. И Form сами объекты автоматически удаляются, когда они закрыты. Это особенно относится к проблеме, поднятой в вашем вопросе. Документация для метода Form.Close сообщает нам следующее:

Когда форма закрыта, все ресурсы, созданные внутри объекта, закрываются и форма удаляется.

[. , , ]

Два условия, когда форма не расположена на Close, - это когда (1) она является частью приложения с интерфейсом с несколькими документами (MDI), а форма не отображается; и (2) вы отобразили форму, используя ShowDialog. В этих случаях вам нужно будет вызвать Dispose вручную, чтобы пометить все элементы управления формой для сборки мусора.

Обратите внимание, что, как правило, вам никогда не придется звонить Form.Dispose вручную из своего кода. Пользователь не может закрыть дочернюю форму MDI, когда его родительский MDI не виден, и если вам случится закрыть форму самостоятельно в коде, когда его родительский элемент невидим, вы можете просто вставить вызов Form.Dispose. Когда вы показываете форму как модальное диалоговое окно с использованием метода ShowDialog, вы можете удобно заключить ее создание и использование в оператор using.

Теперь напомним, что простой вызов метода Dispose для объекта только высвобождает неуправляемые ресурсы и помечает объект как доступный для сборки мусора. Он не сразу освобождает память, требуемую этим объектом. Это важно, потому что именно на этом были сосредоточены ваши попытки профилирования памяти. Вы знаете, что объекты удаляются, потому что вы упоминаете, что переменные становятся недоступными для вас (вы говорите, что «теряете свои значения»). Это потому что вы не можете получить доступ к удаленным объектам. Это не обязательно подразумевает, однако, что память, которую они требовали, была полностью освобождена. Это работа сборщика мусора, которую мы уже установили, с которой вы не должны мириться. Он будет ожидать освобождения памяти до тех пор, пока приложение не будет бездействующим, или ему крайне необходимо повторно использовать этой памяти. В противном случае, он отложит сбор, и все в порядке .

1 голос
/ 04 марта 2011

Вы можете использовать один из доступных профилировщиков памяти, например, ANTS Memory Profiler (см. Использование ANTS Memory Profiler для отслеживания утечки памяти в приложении WinForms ). Вы также можете использовать WinDbg, но без опыта это будет сложнее, чем специализированный инструмент.

Одной из распространенных причин «утечки памяти» является добавление «внешнего» обработчика событий в форму (например, к статическому или долгоживущему объекту), а не удаление его при уничтожении формы, поэтому GC «думает», что у вас есть ссылка на форму, а не собрать свои данные.

Почему и как избежать утечек памяти в обработчике событий?

.NET: пример утечки памяти: обработчики событий, которые создали всплеск памяти

Основы сбора мусора

Распоряжение, завершение и управление ресурсами

Как определить утечки памяти в общеязыковой среде выполнения

Как обнаружить и избежать утечек памяти и ресурсов в приложениях .NET

1 голос
/ 04 марта 2011

Это то, о чем ты не должен заботиться.

.NET Framework Сборщик мусора сделает эту работу за вас.

Сборщик мусора .NET Framework управляет распределением и выпуском память для вашего приложения. Каждый раз вы создаете новый объект, общий язык выполнения выделяет память для объект из управляемой кучи. Как пока адресное пространство доступно в управляемая куча, время выполнения продолжает выделять место для новых объекты.

Редактировать

Вы должны быть уверены, что больше не используете ресурсы, которые смотрели, чтобы быть свободными. Функциональные возможности сборщика мусора находятся в классе GC под пространством имен System.

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

1 голос
/ 04 марта 2011

использовать блок, который автоматически освобождает память

Using { resourcelist | resourceexpression }
    [ statements ]
End Using
0 голосов
/ 04 марта 2011

Использование в соответствии с предложением Pranay будет работать так же, как и при вызове метода Dispose по умолчанию.иначе явно вы должны вызвать this.dispose () после вызова this.close () в ваших дочерних формах.Но убедитесь, что вы не собираетесь использовать дочерние элементы формы или значения после закрытия.Поскольку утилизация окончательно очистит все.

MSDN пример для удаления неуправляемого ресурса

Imports System
Imports System.ComponentModel

' The following example demonstrates how to create
' a resource class that implements the IDisposable interface
' and the IDisposable.Dispose method.
Public Class DisposeExample

   ' A class that implements IDisposable.
   ' By implementing IDisposable, you are announcing that 
   ' instances of this type allocate scarce resources.
   Public Class MyResource
      Implements IDisposable
      ' Pointer to an external unmanaged resource.
      Private handle As IntPtr
      ' Other managed resource this class uses.
      Private component As component
      ' Track whether Dispose has been called.
      Private disposed As Boolean = False

      ' The class constructor.
      Public Sub New(ByVal handle As IntPtr)
         Me.handle = handle
      End Sub

      ' Implement IDisposable.
      ' Do not make this method virtual.
      ' A derived class should not be able to override this method.
      Public Overloads Sub Dispose() Implements IDisposable.Dispose
         Dispose(True)
         ' This object will be cleaned up by the Dispose method.
         ' Therefore, you should call GC.SupressFinalize to
         ' take this object off the finalization queue 
         ' and prevent finalization code for this object
         ' from executing a second time.
         GC.SuppressFinalize(Me)
      End Sub

      ' Dispose(bool disposing) executes in two distinct scenarios.
      ' If disposing equals true, the method has been called directly
      ' or indirectly by a user's code. Managed and unmanaged resources
      ' can be disposed.
      ' If disposing equals false, the method has been called by the 
      ' runtime from inside the finalizer and you should not reference 
      ' other objects. Only unmanaged resources can be disposed.
      Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
         ' Check to see if Dispose has already been called.
         If Not Me.disposed Then
            ' If disposing equals true, dispose all managed 
            ' and unmanaged resources.
            If disposing Then
               ' Dispose managed resources.
               component.Dispose()
            End If

            ' Call the appropriate methods to clean up 
            ' unmanaged resources here.
            ' If disposing is false, 
            ' only the following code is executed.
            CloseHandle(handle)
            handle = IntPtr.Zero

            ' Note disposing has been done.
            disposed = True

         End If
      End Sub

      ' Use interop to call the method necessary  
      ' to clean up the unmanaged resource.
      <System.Runtime.InteropServices.DllImport("Kernel32")> _
      Private Shared Function CloseHandle(ByVal handle As IntPtr) As [Boolean]
      End Function

      ' This finalizer will run only if the Dispose method 
      ' does not get called.
      ' It gives your base class the opportunity to finalize.
      ' Do not provide finalize methods in types derived from this class.
      Protected Overrides Sub Finalize()
         ' Do not re-create Dispose clean-up code here.
         ' Calling Dispose(false) is optimal in terms of
         ' readability and maintainability.
         Dispose(False)
         MyBase.Finalize()
      End Sub
   End Class

   Public Shared Sub Main()
      ' Insert code here to create
      ' and use the MyResource object.
   End Sub

End Class

(обновление) [Проверка]

Если ваша детская форма имеет подпись.По умолчанию они добавляются в форму.

'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
    MyBase.Dispose(disposing)
End Sub
0 голосов
/ 04 марта 2011

Я не эксперт в VB.net, но, насколько я знаю, у него есть сборщик мусора.Обычно это означает, что закрытие дочерних окон не освобождает память, но если вы удалите все ссылки на дочерние окна, сборщик мусора может освободить ее при следующем запуске.

Кроме того, вы обычно можете «попросить» сборщик мусора запустить, но он обычно «сам» решает, когда запускать.

0 голосов
/ 04 марта 2011

Сборщик мусора сделает всю работу за вас, так что вы действительно не должны об этом беспокоиться. Вы должны более глубоко заглянуть внутрь, если и только если вы используете неуправляемые ресурсы (com interop / PInvoke).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...