Параметры C# ссылкой и сборкой "мусора" .NET

Я пытался выяснить запутанность системы сборки "мусора".NET, и мне связали вопрос с параметрами ссылки C#. Если я понимаю правильно, переменные, определенные в методе, хранятся на стеке и не затронуты сборкой "мусора". Так, в этом примере:

public class Test
{
 public Test()
 {
 }

 public int DoIt()
 {
  int t = 7;
  Increment(ref t);
  return t;
 }

 private int Increment(ref int p)
 {
  p++;
 }
}

возвращаемое значение DoIt () будет 8. Так как местоположение t находится на стеке, затем та память не может быть собрана "мусор" или уплотнена, и ссылочная переменная в Инкременте () будет всегда указывать на надлежащее содержание t.

Однако предположите, что мы имеем:

public class Test
{
 private int t = 7;

 public Test()
 {
 }

 public int DoIt()
 {
  Increment(ref t);
  return t;
 }

 private int Increment(ref int p)
 {
  p++;
 }
}

Теперь, t хранится на "куче", поскольку это - значение определенного экземпляра моего класса. Это не возможно проблема, если я передаю это значение как параметр ссылки? Если я передам t как параметр ссылки, то p укажет на текущее местоположение t. Однако, если сборщик "мусора" перемещает этот объект во время компактного, разве который не испортит ссылку на t в Инкременте ()? Или сборщик "мусора" обновляет даже ссылки, созданные путем передачи параметров ссылки? Я должен волноваться об этом вообще? Единственное упоминание о волнении по поводу памяти, уплотняемой на MSDN (что я могу найти), относительно передачи управляемых ссылок на неуправляемый код. Надо надеяться, поэтому я не должен волноваться ни о каких управляемых ссылках в управляемом коде.:)

15
задан skaffman 23 March 2010 в 14:55
поделиться

3 ответа

Если я правильно понимаю, переменные, определенные в методе, хранятся в стеке и на них не влияет сборка мусора.

Это зависит от того, что вы подразумеваете под «затронутым». Переменные в стеке - это корни сборщика мусора, поэтому они, безусловно, влияют на сборку мусора.

Так как t находится в стеке, эта память не может быть собрана или уплотнена, а ссылочная переменная в Increment () всегда будет указывать на правильное содержимое t.

«Не могу» - здесь странное слово. Смысл использования стека в первую очередь заключается в том, что стек используется только для данных, которые никогда не нужно уплотнять и время жизни которых всегда известно , поэтому они никогда не должны быть мусором. собраны. Вот почему мы в первую очередь используем стек. Вы, кажется, ставите телегу впереди лошади.Позвольте мне повторить это, чтобы убедиться, что это ясно: причина, по которой мы храним этот материал в стеке, заключается в том, что он не нуждается в в сборе или уплотнении, потому что его время жизни известно. Если бы время его жизни не было известно, оно отправилось бы в кучу. Например, по этой причине локальные переменные в блоках итератора попадают в кучу.

Теперь t хранится в куче, поскольку это значение определенного экземпляра моего класса.

Верно.

Разве это не проблема, если я передам это значение в качестве ссылочного параметра?

Нет. Хорошо.

Если я передаю t в качестве ссылочного параметра, p будет указывать на текущее местоположение t.

Ага. Хотя я предпочитаю думать об этом так, что p - это псевдоним переменной t.

Однако, если сборщик мусора перемещает этот объект во время сжатия, не испортит ли это ссылку на t в Increment ()?

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

Если вы передали фактический указатель на t с использованием небезопасного кода, тогда вам потребовалось бы закрепить контейнер t на месте, чтобы сборщик мусора знал, что нельзя перемещать Это. Вы можете сделать это с помощью оператора fixed в C # или путем создания GCHandle для объекта, который вы хотите закрепить.

обновляет ли сборщик мусора даже ссылки, созданные путем передачи параметров ссылки?

Ага. В противном случае он был бы довольно хрупким.

Мне вообще нужно об этом беспокоиться?

Нет.Вы думаете об этом как о неуправляемом программисте на C ++ - C ++ заставляет вас делать эту работу, а C # - нет. Помните, что весь смысл модели управляемой памяти состоит в том, чтобы освободить вас от необходимости думать об этом.

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

20
ответ дан 1 December 2019 в 02:55
поделиться

Именно так вы упомянули в последнем предложении. Сборщик мусора переместит все необходимые ссылки при сжатии кучи (кроме ссылок на неуправляемую память).

Обратите внимание, что использование стека или кучи связано с тем, что переменная экземпляра имеет тип значения или ссылки. Типы значений (структуры и «простые» типы, такие как int, double и т. Д.) Всегда находятся в стеке, классы всегда находятся в куче (то, что находится в стеке, является ссылкой - указателем - на выделенную память для экземпляра).

Изменить: как правильно отмечено ниже в комментарии, второй абзац был написан слишком быстро. Если экземпляр типа значения является членом класса, он не будет храниться в стеке, он будет в куче, как и остальные члены.

-1
ответ дан 1 December 2019 в 02:55
поделиться

Нет, вам не о чем беспокоиться. В основном вызывающий метод ( DoIt ) имеет «живую» ссылку на экземпляр Test , что предотвращает его сборку мусора. Я не уверен, можно ли его сжать, но я подозреваю, что это возможно, поскольку сборщик мусора может определять, какие ссылки на переменные являются частью перемещаемых объектов.

Другими словами - не волнуйтесь. Можно ли его уплотнять или нет, это не должно вызывать у вас проблем.

6
ответ дан 1 December 2019 в 02:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: