2017-02-06 18 views
1

Мне было интересно, какие методы лучше всего создавать при создании объектов, выполняя LINQ в C#. Например, я понимаю, что когда я открываю соединение с помощью LINQ я должен поставить объект модели в использовании заявление, как это:Минимизация использования ОЗУ созданными объектами во время выполнения в C#

using(var ctx = new mymodel()) 
{ 

} 

Теперь, что объекты, которые являются EF-классы?

Они не реализуют IDisposable интерфейс, таким образом, я не могу сделать что-то вроде этого, при создании такого объекта, как это, например:

using(var user = new Users()) 
{ 

} 

Но когда действие называется так:

public ActionResult InsertUser() 
{ 

    var user = new Users(); 

} 

У меня нет четкого представления о том, что происходит с этим объектом после завершения вставки в db. Остается ли этот объект выделенным в памяти или он будет выпущен? Если нет, то каковы лучшие практики для выпуска памяти, когда они больше не нужны.?

С другой стороны есть статические переменные, а также ...

Итак, чтобы подвести вещи, мои вопросы:

  • какие лучшие практики для освобождения памяти при создании экземпляра объекта класса?

  • Является ли реализация IDisposable интерфейса для каждого класса, который у меня есть хороший выбор?

  • Когда статическая переменная создается в .NET MVC, каков наилучший способ освобождения памяти от таких переменных?

  • Тот же вопрос касается объекта Session?

P.S. Ребята, я был бы очень признателен, если бы вы все читали это, чтобы опубликовать свое мнение или опубликовать некоторые полезные ссылки для некоторых публикаций в документах/блогах, чтобы я мог расширить свои горизонты.)

+1

У вас есть проблема с потреблением памяти? – trailmax

+1

Объекты собираются, когда они выходят за рамки. Если никакие области активного кода не ссылаются на объект или дерево объектов, которое косвенно ссылается на него, оно будет собрано. Вам нужно только реализовать 'IDisposable' на классах, у которых есть неуправляемые ресурсы, которые необходимо очистить. – Amy

+0

@trailmax Да, это именно та проблема, я не знаю, откуда она взялась, но мне нужно разобраться, чтобы максимизировать эффективность моего кода. =) – User987

ответ

4

Прежде чем делать какие-либо улучшения производительности настоятельно рекомендуем запускать профилировщик памяти (например, JetBrains dotMemory, но есть и другие) и выяснить фактический источник проблемы. Без информации от профилировщика, ваши оптимизации будут похожи на то, чтобы вставлять палец в небо и кричать «Радуга!». то есть бесполезно в лучшем случае, вредно в худшем случае.

Также после выявления проблем с профилировщиком, но перед тем, как приступить к изменению кода, я рекомендую прочитать о том, как сборка мусора работает в .Net.Вот некоторые ссылки, чтобы вы начали:

  1. MSDN Garbage Collection
  2. MSDN Garbage Collector Basics and Performance Hints
  3. .Net Garbage Collection in depth

Вот некоторые ссылки, чтобы ответить на ваши вопросы:

+0

Отличный ответ, спасибо! =) – User987

+0

@ User987 добавил немного больше ссылок на ваши конкретные вопросы – trailmax

2

В ответ на комментарий.

Когда вы создаете обычный .NET-объект, среда выполнения .NET знает обо всем, потому что среда выполнения создала его. Он знает, где в памяти он находится, когда он больше не нужен и так далее. Когда он больше не нужен, среда выполнения восстановит свою память. Это управляется (по времени выполнения) объектом. Вы не должны заботиться об управлении памятью для таких объектов.

Теперь возьмите, например, ручку файла. Когда вы открываете файл в .NET, он делегирует эту операцию ОС (например, Windows). Этот ресурс не управляется средой выполнения, он управляется ОС. Таким образом, это неуправляемый ресурс. Поэтому автор кода библиотеки .NET, который работает с файлами (я имею в виду человека, который создал FileStream и аналогичные классы, а не , использует их) должен вручную написать код для выпуска такого ресурса (закройте в этом случае дескриптор файла). По соглашению автор будет использовать метод IDisposable.Dispose для кода, который освобождает такие ресурсы И гарантирует, что когда базовый объект (например, FileStream) будет собран GC - неуправляемые ресурсы также будут выпущены. Так что даже если вы забудете позвонить Dispose - дескриптор файла будет закрыт, когда GC собирает FileStream (не то, что это произойдет не волшебным образом, но , потому что автор кода явно сделал это так). Но это может произойти в любое время в будущем, вы не хотите оставлять дескриптор файла открытым в течение неопределенного времени, поэтому вы всегда вызываете Dispose самостоятельно, когда вы закончите с объектом IDisposable.

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

Или предположим, что вы пишете свой собственный код для работы с изображениями с помощью ImageMagick. Это библиотека C, поэтому среда выполнения не имеет представления о ее внутренней работе. Вы просите библиотеку выделить память для вашего изображения, но .NET не может восстановить такую ​​память - она ​​не управляется, она управляется библиотекой ImageMagick C. Итак, вы реализуете IDisposable и сообщаете ImageMagick о выпуске памяти в этом методе.

0

В случае var user = new Users();, который не реализует IDisposable, и любой объект, который не расположен, будет гарантированно существовать там, где есть активная ссылка на этот объект; после чего он будет иметь право на удаление в следующий раз, когда сборщик мусора (GC) попытается освободить память.

В приведенном выше примере, как только он покинет метод InsertUser(), у него больше не будет ссылок, указывающих на него, и, следовательно, он будет предназначен для сбора мусора.

Если, однако, существует ссылка, например, в следующем коде, объект не будет удален до тех пор, пока ссылка не будет очищена или не будет размещен содержащийся класс.

private User _insertedUser; 

public ActionResult InsertUser() 
{ 

    _insertedUser = new Users(); 

} 

Сборщик мусора запускается, когда приложение должно освободить память. Когда он срабатывает, он выполняет несколько разверток на объектах в памяти, чтобы определить, существуют ли какие-либо ссылки. Сначала он сканирует каждый объект, который был недавно создан с момента последнего вызова GC. Объектам, переживающим этот размах, способствуют поколение. Если после развертки требуется еще больше памяти, выполняется развертка 2-го поколения. Это сканирует каждый объект, который пережил единую сборку мусора, чтобы узнать, может ли она теперь быть освобождена. Опять же, если объект выживает, он перемещается в другое поколение, всего в 3 поколения.

Этот метод помогает GC выполнять управление памятью, ограничивая при этом высокие затраты (более новые объекты, скорее всего, будут доступны для выпуска). Поскольку GC имеет высокую стоимость, связанную с этим, лучше, если объекты удаляются через код пользователя, чтобы ограничить количество вызовов GC.

tldr;

  • Утилизируйте объекты, если они реализуют IDisposable; простой способ - это окружает его с помощью «использования».
  • Если объект не может быть удален, и он больше не требуется, убедитесь, что все ссылки на объект очищены (особенно ссылки за пределами метода, который был создан объектом). Это позволяет GC выпустить его из памяти.