Большинство программистов C# напрямую не сталкивается с подробностями размещения данных в памяти, подробные данные нужны только опытным программистам для оптимизации скорости работы программы. Но основы надо знать всем - сейчас поймете почему. Для любых данных нужно место в памяти компьютера. В некоторых языках вроде C и C++ программистам надо вручную выделять его при создании переменных и освобождать после завршения их использования, сталкиваясь с ошибками вроде утечек памяти.
В C# дела обстоят иначе. Для самых простых типов данных память компьютера выделяется автоматически, написав int counter; мы автоматически получим место в памяти, в которое будет по умолчанию записан 0.
Но большая часть данных хранится в экземплярах классов, память для которых выделяется при использовании ключевого слова new. По большому счету это тоже происходит автоматически, а после завершения использования обьекта память высвобождается сборщиком мусора. Но такие переменные являются ссылочными типами данных и ведут себя иначе. В них хранятся не сами данные, а ссылка на область в памяти с этими данными. Если в одну переменную записать значение другой переменной, то они обе будут указывать на одно и то же значение. Вот код, наглядно демонстрирующий эту разницу
|
|
string surname1 = "Пушкин ";
string surname2 = "Гончарова";
// в surname1 записывается значение surname2 но сами переменный продолжают существовать независимо
surname1 = surname2;
surname2 = "ААА";
Console.WriteLine("Значение surname1: " + surname1); // Гончарова
Console.WriteLine("Значение surname2: " + surname2); // ААА
Person person1 = new Person("Пушкин", "Александр", "Сергеевич");
Person person2 = new Person("Гончарова", "Наталья", "Николаевна");
// в person1 записывается ссылка на обьект person2 теперь обе переменные ссылаются на один и тот же обьект класса Person
person1 = person2;
person2.Surname = "AAA";
Console.WriteLine("Значение person1.Surname: " + person1.Surname); // ААА
Console.WriteLine("Значение person2.Surname: " + person2.Surname); // ААА
Console.ReadLine();
Отличие структур от классов без функций в том, что данные структуры копируются из одной в другую при записи одной переменной в другую, а при записи одной ссылочной переменной в другую копируется только ссылка на данные, что при большом объеме данных может работать намного быстрей.
С другой стороны, чтобы реально скопировать данные из одного объекта ссылочной типа в другой (и в итоге получить два разных объекта с одинаковыми данными, а не две ссылки на один и тот же) придется писать специальный код.
Когда именно какой-то объект становится ненужным и попадает под внимание сборщика мусора? На самом деле особенности работы сборщика мусора относятся к достаточно продвинутым и глубоким вопросам, так как это очень умная машина. Но как минимум одно связанное с этим понятие надо знать любому программисту - область видимости переменных. В большинстве случаев мы потеряем контроль над переменной после того, как она выйдет из этой области видимости - после этого она больше не будет доступна программисту и рано или поздно ее память будет освобождена сборщиком мусора. В большинстве случаев область видимости переменной ограничивается блоком кода, ограниченным двумя фигурными скобками. Если внутри такого блока есть еще один блок - то на него распространяется область видимости родительского блока. Пример сферической области видимости в вакууме
|
|
{
int testVariable = 1;
}
testVariable = 2; // такая программа просто не скомпиллируется, прямо в VisualStudio выдаст ошибку The name 'testVariable' does not exist in the current context
А вот так все будет в порядке.
int testVariable = 1;
{
testVariable = 2;
}
Другой вариант первой ошибки
int testVariable = 1;
{
int testVariable = 2;
}
А вот так все будет в порядке, поскольку переменные с одним и тем же именем объявляется в разных областях видимости одного и того же уровня, не зависящих друг от друга
{
int testVariable = 2;
Console.WriteLine(testVariable);
}
{
int testVariable = 2;
Console.WriteLine(testVariable);
}
Само собой в реальном программировании пустые блоки фигурных скобок не применяются, но все вышесказанное верно для всех тех случаев, когда они применяются осмысленно - логических условий, циклов, функций.
Наглядный пример более сложной задачи, при решении о которой необходимо помнить об особенностях работы сборщика мусора - использование Word для вывода данных в отчеты. В этом случае мы используем ресурс, неподвластный сборщику мусора - программу Word, запускаемую и управляемую из нашего кода. Если она становится не нужна, то ее надо закрывать вручную из кода - иначе на компьютере начнут плодится невидимые Word'ы в неограниченных количествах.