Кажется, что каждая книга .net говорит о типах значений по сравнению со ссылочными типами и указывает на то, что (часто неправильно) указывает состояние, в котором хранится каждый тип - куча или стек. Обычно это в первых нескольких главах и представлено как какой-то очень важный факт. Я думаю, что это даже покрыто на сертификационных экзаменах . Почему стек и куча имеют значение для начинающих разработчиков .Net? Вы распределяете вещи, и это просто работает, верно?
36
Ответы:
Я становлюсь убежденным, что основной причиной, по которой эта часть информации считается важной, является традиция. В неуправляемых средах различие между стеком и кучей важно, и мы должны вручную распределять и удалять используемую нами память. Теперь сборщик мусора заботится об управлении, поэтому они игнорируют этот бит. Я не думаю, что сообщение действительно получило, что нам не нужно заботиться о том, какой тип памяти используется.
Как отметил Феде, у Эрика Липперта есть кое-что очень интересное по этому поводу: http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx ,
В свете этой информации вы можете изменить мой первый абзац следующим образом: «Причина, по которой люди включают эту информацию и полагают, что она важна, связана с неправильной или неполной информацией в сочетании с необходимостью этих знаний в прошлом».
Для тех, кто считает, что это все еще важно по соображениям производительности: какие действия вы бы предприняли, чтобы переместить что-то из кучи в стек, если бы вы измеряли вещи и выясняли, что это имеет значение? Скорее всего, вы найдете совершенно другой способ повышения производительности для проблемной области.
источник
Я полностью согласен; Я вижу это все время.
Одна из причин в том, что многие люди пришли на C # (или другие языки .NET) из C или C ++ фона. Поскольку эти языки не обеспечивают для вас правил срока хранения, вам необходимо знать эти правила и тщательно выполнять свою программу, чтобы следовать им.
Теперь, зная эти правила и следуя им в C, не требуется, чтобы вы понимали «кучу» и «стек». Но если вы понимаете, как работают структуры данных, то зачастую легче понять и следовать правилам.
При написании книги для начинающих для автора естественно объяснить концепции в том же порядке, в котором они их выучили. Это не обязательно порядок, который имеет смысл для пользователя. Недавно я был техническим редактором книги Скотта Дормана для начинающих на C # 4, и мне понравилось то, что Скотт выбрал довольно разумный порядок тем, вместо того, чтобы начинать с действительно сложных тем в управлении памятью.
Другая часть причины заключается в том, что некоторые страницы в документации MSDN сильно подчеркивают соображения хранения. Особенно старая документация MSDN, которая до сих пор существует. Большая часть этой документации содержит тонкие ошибки, которые никогда не были удалены, и вы должны помнить, что она была написана в определенное время в истории и для определенной аудитории.
На мой взгляд, это не так. Гораздо важнее понимать такие вещи, как:
И так далее.
Это идеал.
Теперь есть ситуации, в которых это имеет значение. Сборка мусора потрясающая и относительно недорогая, но не платная. Копирование небольших структур вокруг относительно недорого, но не бесплатно. Существуют реалистичные сценарии производительности, в которых вы должны сбалансировать стоимость давления сбора и стоимость чрезмерного копирования. В этих случаях очень полезно иметь четкое представление о размере, расположении и фактическом сроке службы всей соответствующей памяти.
Точно так же существуют реалистичные сценарии взаимодействия, в которых необходимо знать, что находится в стеке, а что в куче, и что может перемещать сборщик мусора. Вот почему в C # есть такие функции, как «fixed», «stackalloc» и так далее.
Но это все продвинутые сценарии. В идеале начинающему программисту не нужно беспокоиться ни об этом.
источник
Вы, ребята, все упускаете суть. Причина, почему различие стека / кучи важно из-за области видимости .
Как только x выходит из области видимости, созданный объект категорически исчезает . Это только потому, что он расположен в стеке, а не в куче. В «...» части метода нет ничего, что могло бы изменить этот факт. В частности, любые присваивания или вызовы методов могли только создавать копии структуры S, но не создавать новые ссылки на нее, чтобы она могла продолжать жить.
Совершенно другая история! Поскольку x теперь находится в куче , его объект (то есть сам объект , а не его копия) вполне может продолжать жить после того, как x выходит из области видимости. Фактически, единственный способ, которым он не будет продолжать жить, - это если х - единственная ссылка на него. Если присваивания или вызовы метода в части «...» создали другие ссылки, которые все еще «живы» к тому времени, когда x выходит из области видимости, тогда этот объект будет продолжать жить.
Это очень важная концепция, и единственный способ по-настоящему понять «что и почему» - это узнать разницу между стеком и распределением кучи.
источник
...
может привестиx
к преобразованию в поле сгенерированного компилятором класса и, таким образом, превзойти указанную область видимости. Лично я нахожу неприятным идею неявного поднятия, но разработчики языка, кажется, идут на это (в отличие от требования, чтобы любая переменная, которая была поднята, имела что-то в своем объявлении, чтобы указать это). Чтобы гарантировать корректность программы, часто необходимо учитывать все ссылки, которые могут существовать на объект. Зная, что к тому времени, когда подпрограмма вернется, никакая копия переданной ссылки не останется полезной.structType foo
, то место храненияfoo
содержит содержимое его полей; еслиfoo
в стеке, то и его поля. Еслиfoo
есть в куче, то и его поля. Еслиfoo
в сетевом Apple II, так же, как и его поля. В противоположность этому , еслиfoo
были типом класса, он будет проводить либоnull
, или ссылка на объект. Единственная ситуация, в которойfoo
можно сказать, что тип класса содержит поля объекта, была бы, если бы оно было единственным полем класса и содержало ссылку на себя.Что касается ПОЧЕМУ они охватывают тему, я согласен с @Kirk, что это важная концепция, которую вы должны понять. Чем лучше вы знаете механизмы, тем лучше вы сможете создавать великолепные приложения, которые работают без сбоев.
Теперь Эрик Липперт, похоже, согласен с вами, что эта тема не совсем правильно освещена большинством авторов. Я рекомендую вам прочитать его блог, чтобы добиться отличного понимания того, что находится под капотом.
источник
Ну, я думал, что в этом весь смысл управляемых сред. Я бы даже сказал, что это деталь реализации базовой среды выполнения, о которой НЕ следует делать никаких предположений, потому что она может измениться в любое время.
Я не знаю много о .NET, но, насколько я знаю, его JITted перед выполнением. JIT, например, может выполнять анализ escape, а в противном случае у вас будут объекты, лежащие в стеке или просто в некоторых регистрах. Вы не можете знать это.
Я предполагаю, что некоторые книги освещают это просто потому, что авторы придают большое значение этому, или потому что они полагают, что их аудитория это делает (например, если вы написали «C # для программистов на C ++», вы, вероятно, должны охватить эту тему).
Тем не менее, я думаю, что сказать намного больше, чем «память управляется». В противном случае люди могут сделать неправильные выводы.
источник
Вы должны понимать, как работает распределение памяти, чтобы эффективно использовать его, даже если вам не нужно управлять им явно. Это относится практически ко всем абстракциям в информатике.
источник
Могут быть некоторые крайние случаи, когда это может иметь значение. Размер стека по умолчанию составляет 1 мг, а куча - несколько гигабайт. Поэтому, если ваше решение содержит большое количество объектов, вы можете исчерпать пространство стека, имея достаточно места в куче.
Тем не менее, по большей части это довольно академично.
источник
Как вы говорите, C # должен абстрагироваться от управления памятью, а распределение кучи и стека - это детали реализации, о которых, теоретически, разработчик не должен знать.
Проблема в том, что некоторые вещи действительно трудно объяснить интуитивно понятным способом, не обращаясь к этим деталям реализации. Попытайтесь объяснить наблюдаемое поведение при изменении типов изменяемых значений - это почти невозможно сделать без ссылки на различие стека / кучи. Или попытайтесь объяснить, почему в языке вообще есть типы значений и когда вы их используете? Вы должны понимать разницу, чтобы понять язык.
Обратите внимание, что книги о Python или JavaScript не имеют большого значения из этого, если они даже упоминают об этом. Это потому, что все либо выделено кучей, либо неизменным, что означает, что разные семантики копирования никогда не вступают в игру. В этих языках работает абстракция памяти, в C # она протекает.
источник