#c_sharp #ооп
Класс ведь ссылочный тип, а переменные в классе могут быть типами по значению. Например: class Car { public int maxSpeed; public Car(int max) { maxSpeed = max; } } Где хранится maxSpeed — в стеке или куче?
Ответы
Ответ 1
Сам по себе вопрос вызван двумя проблемами достаточно распространенным, но в общем случае неверным утверждением "переменные value-type хранятся в стеке" небольшой путаницей в терминологии - поля класса это не "переменные" - не локальные переменные. Дело в том, что на уровне языка C# нет понятия "стэк" и "куча". Есть два вида типов: Ссылочные. Значение переменной или поля класса этого типа хранит в себе адрес памяти, по которому лежит экземпляр типа. Сам по себе экземпляр при этом обычно лежит в куче. Пример - строки. Value-types (типы-значения). Значение переменной или поля класса хранит значение напрямую. Пример - int. Понятие стека есть на уровне .NET/IL. Локальные переменные в методах уровня IL .NET хранятся в стеке. Переменная C# превращается в переменную метода IL далеко не всегда. Это происходит, если: на нее нет замыканий она объявлена в не-async-методе еще много разных условий, вызванных особенностями реализации конкретного компилятора C#. Поля типов хранятся как часть самого экземпляра типа. Они физически лежат в том куске памяти, который выделен под конкретных экземпляр типа. Т.е. если экземпляр сам по себе лежит в стеке (например, это экземпляр структуры) - то поле хранится в стеке. Если экземпляр лежит в куче - то и поле лежит в куче. Конкретные примеры В методе объявлен int a - он лежит прямо в стеке В методе объявлен string s - в переменной в стеке лежит адрес строки в куче. В методе объявлен Car c - в переменной в стеке лежит адрес объекта Car. Сам объект лежит в куче. Частью объекта в куче является поле maxSpeed, в нем лежит значение скорости. В методе объявлен int [] arr - в переменной в стеке лежит адрес массива в куче. Прямо в объекте массива в куче лежат значения отдельных ячеек. Объявлена структура Point с полями X/Y. В методе объявлена переменная Point p - в переменной в стеке лежит сама структура, со всеми полями.Ответ 2
Перевод ответа на аналогичного вопрос на английском Типы-значения называются "типы-значения", потому что копируются по значению. Ссылочные типы называются "ссылочными типами", потому что копируются по ссылке. Это не совсем верно, что "типы-значения всегда находятся на стеке". Если бы это было правдой они бы назывались "Типы стека"(stack types) и "Типы кучи"(heap types). Правда в том, что все зависит от деталей реализации. Различные реализации фреймворков могут выбирать использовать им стек или кучу, так как они хотят. Ниже пример как это реализовано у Микрософта: значение переменной ссылочного типа указывает на значение в куче. Ссылки в основном 32-х или 64-х битное целое. значение переменной значимого типа - это само значение. значения локальных переменных хранятся на стеке, пока эти переменные не в блоке итератора, или не замкнуты в анонимном методе или лямбда-выражении. В этих случаях значения локальных переменных хранятся в куче. Конечно, пока эти переменные не выкинуты оптимизатором, в этом случае они нигде не хранятся. Или, возможно они могут быть перенесены в регистры и в этом случае они не будут ни на стеке, ни в куче. значения экземпляров ссылочных типов и статические переменные хранятся в куче. maxSpeed - это поле, следовательно, хранится в куче. Единственная вещь идущая в стек - это локальные переменные (и временные переменные сгенерированные компилятором), которые не замкнуты в лямбда функциях или анонимных методах, и не находятся в блоке итератора. И, конечно, jitter может не использовать стек, а сложить все в регистры, если достаточно свободных регистров. Но, на самом деле, я должен спросить: почему вы беспокоитесь о том, что пойдет в стек, а что в кучу? В стек идет только то, что мы можем быстро положить в него, все остальное идет в кучу.Ответ 3
Объекты класса хранятся в куче. А что представляет собой экземпляр класса? По-сути, тип да набор своих переменных. А в стеке хранятся те переменные, которые объявляются внутри функций/методов. Отсюда и проблема переполнения стека при чрезмерном рекурсивном вызове функций (см. название сайта :)).
Комментариев нет:
Отправить комментарий