close

Вход

Забыли?

вход по аккаунту

?

23 89 ООПиП Понкратов

код для вставкиСкачать
23. Понятие ссылочного и размерного типов. Упаковка и распаковка размерных типов. Размещение ссылочных и размерных типов в памяти.
CLR поддерживает две разновидности типов: ссылочные (reference types) и размерные (value types). Чаще всего вам придется иметь дело с ссылочными типами. Память для них всегда выделяется из управляемой кучи, а оператор new возвращает адрес в памяти, где размещается сам объект. При работе с ссылочными типами имейте в виду следующие обстоятельства, относящиеся к производительности приложения:
-память для ссылочных типов всегда выделяется из управляемой кучи;
-каждый объект, размещаемый в куче, имеет некоторые дополнительные члены, подлежащие инициализации;
-размещение объекта в управляемой куче со временем инициирует сборку мусора.
Если бы все типы были ссылочными, то эффективность приложения резко снизилась бы. Представьте, насколько замедлится выполнение приложения, если при каждом обращении к значению типа Int32 будет распределяться память! Поэтому, чтобы ускорить обработку простых, часто используемых типов, CLR преагает "облегченные" типы - размерные. Экземпляры этих типов обычно размещаются в стеке потока.
В представляющей экземпляр переменной нет указателя на экземпляр; поля экземпляра размещаются в самой переменной. Благодаря тому, что экземпляры размерных типов не обрабатываются сборщиком мусора, уменьшается интенсивность работы с управляемой кучей.
// Ссылочный тип (поскольку 'class'). class SomeRef { public Int32 x; } //Размерный тип (поскольку 'struct'). struct SomeVal { public Int32 x; }
static void ValueTypeDemo() {
SomeRef rl = new SomeRef(); // Размещается в куче.
SomeVal vl = new Someval(); // Размещается в стеке.
rl x = 5; // Разыменовываем указатель.
vl.x = 5;// иэм енения в стеке.
Console.WriteLine(r 1.х); // Отображается " 5".
Console.WriteLine(v1.x); // Также отображается "5".
SomeRef r2 = rl; // Копируется только ссылка (указатель).
SomeVal v2 = vl; // Помещаем в стек и копируем члены.
rl .х = 8;// Изменяются rl .x и г2.х.
vl х = 9;// Изменяется vl.x, но не v2.x.
Console.WriteLine(rl.x); //Отображается "8".
Console.WriteLine(r2.x); //Отображается "8".
Console.WriteLine(vl.x); //Отображается "9".
Console.WriteLine(v2.x); //Отображается "5".
}
В этом примере тип SomeVal объявлен с ключевым словом struct, а не с помощью более популярного слова class. В С# типы, объявленные как struct, являются размерными. а объявленные как class - ссылочными. В предыдущем примере есть строка:
SomeVal vl = new SomeVal(); // Размещается в стеке
Может показаться, что экземпляр SomeVal будет помещен в управляемую кучу. Но поскольку компилятор С# знает, что SomeVal является размерным типом, в сформированном им коде экземпляр SomeVal будет помещен в стек потока. С# также гарантирует обнуление всех полей экземпляра, имеющего размерный тип. Проектируя свой тип, посмотрите, не использовать ли вместо ссылочного типа размерный. Иногда это может повысить эффективность кода. Особенно это справедливо для типа, удовлетворяющего всем перечисленным ниже условиям.
• Тип ведет себя подобно элементарному типу.
• Типу не нужен любой другой тип в качестве базового.
• Тип не будет иметь производных от него типов.
• Экземпляры этого типа редко передаются методам в качестве параметров. • Экземпляры этого типа редко возвращаются методами.
• Экземпляры этого типа редко используются в наборах, таких как Array List.
Основное достоинство размерных типов в том, что они не размещаются в управляемой куче.
Упаковка и распаковка размерных типов
Размерные типы "легче" ссылочных: для них не нужно выделять память в управляемой куче, их не затрагивает сборка мусора и к ним нельзя обратиться через указатель. Однако часто нужно получить ссылку на экземпляр размерного типа. Скажем, вы хотите сохранить структуры Point в объекте типа ArrayList (определен в пространстве имен System.Collections). В коде это выглядит примерно так:
// Объявляем размерный тип. struct Point {
public Int32 x, у;
}
class App {
static void Main() {
ArrayList a = new ArrayList();
Point p; // Выделяется память для Point (не в куче).
for (Int32 i = 0; i < 10; i++) {
p.x = p. у = i; // Инициализация членов в нашем размерной типе.
a.Add(p); // Упаковка размерного типа и добавление // ссылки в ArrayList. }
}}
Но в нашем примере передается переменная р, имеющая размерный тип Point. Чтобы код работал, нужно преобразовать размерный тип Point в объект из управляемой кучи и получить на него ссылку.
Преобразование размерного типа в ссылочный позволяет выполнить упаковка (boxing). При упаковке экземпляра размерного типа происходит следующее.
1.В управляемой куче выделяется память. 2. Поля размерного типа копируются в память, выделенную только что в куче.
3. Возвращается адрес объекта. Познакомившись с упаковкой, перейдем к распаковке. Допустим, в другом месте кода вам нужно извлечь первый элемент массива ArrayList:
Point p = (Point) a[0];
Здесь ссылку (или указатель), содержащуюся в элементе с номером 0 массива ArrayList, вы пытаетесь поместить в переменную р размерного типа Point. Для этого все поля, содержащиеся в упакованном объекте Point, должны быть скопированы в переменную р размерного типа, находящуюся в стеке потока. CLR выполняет эту процедуру в два этапа. Сначала извлекается адрес полей Point из упакованного объекта Point. Этот процесс называется распаковкой (unboxing). Затем значения полей копируются из кучи в экземпляр размерного типа, находящийся в стеке.
Документ
Категория
Разное
Просмотров
18
Размер файла
22 Кб
Теги
понкратов, оопип
1/--страниц
Пожаловаться на содержимое документа