wildHunt
@wildHunt

Разница в работе памяти и ссылок в C# и Python?

В Питоне насколько я понимаю полностью ссылочная модель. Сама переменная ничего не хранит и это просто ссылка на объект. Соответственно, когда я перезаписываю данные в переменной, то старый объект удаляется если на него больше нет ссылок и наша переменная начинает ссылаться на другой объект:
a = 10
a = 20  # 10 будет удален


Интересно как в С# с этим, особенно различие value и reference типов. Не уверен, но мне кажется, что ситуация с ссылочными типами должна быть примерно идентична с Питоном. Если я делаю так, то переменная просто начинает ссылаться на другой объект, а старый будет удален когда отработает сборщик мусора:
var my_list = new List<int> {1, 3, 5};
my_list = new List<int>{4, 5, 6};  // List<int> {1, 3, 5} будет удален?


Но что происходит, когда я так делаю с value типами? Ссылки тут нет (нет же?) и как я понял, то переменная с value типом хранит сам объект, а не ссылку на объект. Получается, my_number просто перезапишет значение с 10 на 20 и все?
int my_number = 10;
my_number = 20;


Читал про стэк, но ясного понимания пока нет. Как будто выходит так, что когда я пишу int my_number = 10, то в конец стэка попадает число 10. А когда затем пишу my_number = 20, то 10 уходит из стэка (удаляется совсем?) и туда попадает число 20.
  • Вопрос задан
  • 173 просмотра
Решения вопроса 1
Griboks
@Griboks Куратор тега C#
Разница в работе памяти и ссылок в C# и Python?

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

ситуация с ссылочными типами должна быть примерно идентична с Питоном

Да, ситуация очень похожа, и в большинстве случаев так и будет работать. Но как я и предупреждал: "The actual lifetime of a local variable is implementation-dependent."

Но что происходит, когда я так делаю с value типами?

В действительности существует 7 категорий переменных, о которых можно прочитать по ссылке.

Ссылки тут нет (нет же?) и как я понял, то переменная с value типом хранит сам объект, а не ссылку на объект.

Значимые типы могут содержать ссылки, поэтому сборщик мусора молчаливо удалит лишь оболочку и любезно предоставит вам утечку памяти, но это очень редкий случай. В большинстве случаев можно сказать, что значимая переменная хранит значение. Причём не просто хранит, а копирует его при присваивании ("Assignment to a variable of a value type creates a copy of the value being assigned. ").

Получается, my_number просто перезапишет значение с 10 на 20 и все?

Хороший вопрос, но в нём есть подвох. Выражение int my_number = 10; ничего никуда не записывает, а инициализирует - создаёт привязку переменной my_number к ячейке памяти с числом 10 на этапе компиляции. В итоге ваш пример записывает новое значение в переменную всего один раз и завершается.

Кроме того, это новое значение вовсе и не значение, а литерал. Встаёт ряд вопросов: "Литералы тоже копируются согласно спецификации, или компилятор умнее?" А если компилятор умный, то почему бы ему не объединить этот код в int my_number = 20; на этапе компиляции? Тут уже не лишним и исходники компилятора + виртуальной машины посмотреть.

Читал про стэк, но ясного понимания пока нет.

Со стеком всё более-менее просто, если не разбираться, какие типы в какой памяти хранятся. Все операции можно разложить в граф, а из графа собрать цепочку простейших операций, которая при обработке LIFO реализует алгоритм. Так вот эта цепочка и называется стеком вызовов. Аналогично существует стек данных.

p.s.
На всякий случай хочу заметить, что в питоне тоже не всё так просто и очевидно. Например:
x = 1; print(id(x))
x = 2; print(id(x))
y = 1; print(id(y))
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
vabka
@vabka Куратор тега C#
Токсичный шарпист
Да, всё верно.
Ответ написан
yarosroman
@yarosroman Куратор тега C#
C# the best
Локальные переменные хранятся на стекле, и им выделяется конкретное место. В случае
int my_number = 10;
my_number = 20;

Перезапишется значение на стеке.

Да и нникаких оптимизаций при компиляции в байт код не делается, это делает JIT и то при release сборке. Все ненужные присваивания и неиспользуемые переменные выкидываются.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы