Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Garbage Collector


Автор: Azzdorf 11.7.2007, 14:31
Тут вопросик общего плана. Программа создает Кучу и Стек.
Куча умерает ли вместе с программой????
А GAC чистит только стек????

И каким методом можна автоматически запускать Garbige Collector в нужный момент времени...

Автор: QryStaL 11.7.2007, 16:19
Код

GC.Collect()

Автор: ivashkanet 11.7.2007, 17:08
Цитата(Azzdorf @  11.7.2007,  14:31 Найти цитируемый пост)
Куча умерает ли вместе с программой????

Конечно. Об этом заботиться среда .Net 
Цитата(Azzdorf @  11.7.2007,  14:31 Найти цитируемый пост)
А GAC чистит только стек????

Нет, только кучу
Стек вообще никто не чистит специально. Он так устроен, что чиститься автоматически и задумываться об его очистке не надо

Автор: Azzdorf 11.7.2007, 20:41
Цитата(ivashkanet @ 11.7.2007,  17:08)
Нет, только кучу
Стек вообще никто не чистит специально. Он так устроен, что чиститься автоматически и задумываться об его очистке не надо

А что там чистить в Куче и Что GAC чистит в стеке????

Автор: mr.DUDA 11.7.2007, 20:48
Стек - вообще интересное понятие. Вот кто например может мне сказать, почему массивы хранятся вне памяти метода (т.е. в куче), однако элементы массива являются value type? Это что, означает что есть некая память называемая стековой, но таковой не являющаяся?

 smile 

Автор: Azzdorf 11.7.2007, 21:05
Цитата(mr.DUDA @ 11.7.2007,  20:48)
Стек - вообще интересное понятие. Вот кто например может мне сказать, почему массивы хранятся вне памяти метода (т.е. в куче), однако элементы массива являются value type? Это что, означает что есть некая память называемая стековой, но таковой не являющаяся?

 smile

 smile  и как тогда мона в этом разобратся?????
 smile  как минимум нужен отдельный форум по GAC.... smile

Добавлено через 1 минуту и 5 секунд
Цитата(QryStaL @ 11.7.2007,  16:19)
Код

GC.Collect()

он сам пройдется, освободит файл и вырубиться7??? smile 

Автор: tol05 11.7.2007, 21:23
Цитата(mr.DUDA @  11.7.2007,  20:48 Найти цитируемый пост)
почему массивы хранятся вне памяти метода (т.е. в куче), однако элементы массива являются value type

Я могу smile
По той же причине в куче хранятся, по которой и класс типа
Код

class A
{
   int x;
   int y;
}

массивы, это те же классы, содержащие свойства, методы и поля...

Цитата(mr.DUDA @  11.7.2007,  20:48 Найти цитируемый пост)
есть некая память называемая стековой, но таковой не являющаяся

да нет. есть просто стековая память и куча. В стековой памяти хранятся value-объекты и ссылки на reference-объекты. Когда выходим из метода стек чистится полностью, т.е. ячейки с value-объектами очищаются и ячейки со ссылками на reference-объекты очищаются тоже. В итоге мы имеем reference-объекты, на которые никто не указывает (недостижимые объекты, добыча GC)
В случае с массивом, ссылка на него изчезнет, а массив - останется в куче до сборки мусора...

Azzdorf могу посоветовать почитать http://forum.vingrad.ru/forum/topic-151484/anchor-entry1136956/15.html, может что-то прояснится по GC

И не путай GC с GAC - это разные вещи  smile 

Автор: mr.DUDA 11.7.2007, 21:32
Цитата(tol05 @  11.7.2007,  21:23 Найти цитируемый пост)
 Когда выходим из метода стек чистится полностью, т.е. ячейки с value-объектами очищаются и ячейки со ссылками на reference-объекты очищаются тоже. В итоге мы имеем reference-объекты, на которые никто не указывает (недостижимые объекты, добыча GC)


Цитата(tol05 @  11.7.2007,  21:23 Найти цитируемый пост)
В случае с массивом, ссылка на него изчезнет, а массив - останется в куче до сборки мусора...

Противоречие: стек чистится = вся память занятая под стек очищается = все объекты выделенные на стековой памяти удаляются
Вопрос 1: куда при этом деваются объекты (структуры, инты и т.п.) хранимые в массиве? Они ведь value type а не reference type, и в отличие от массива должны быть выделены на стеке. Почему же они остаются жить после очистки стековой памяти?
Вопрос 2: как GC рассматривает объекты, созданные на стеке но хранимые в массиве? Как часть reference-типа? То есть попадают ли они в поколения, собираемые GC?  

З.Ы. Судя по тому что я видел в .NET Memory Profiler, даже простейшие int-ы собираются GC вплоть до 1-2 поколений сборки мусора. Но это объяснимо в случае если они боксятся. В случае же массивов, как и generic-ов заявляемые мелкософтом возможности гарантируют что простейшие типы не будут бокситься, если они лежат в массиве или одной из generic-коллекций (кстати, все generic-коллекции так или иначе юзают массивы). Что же тогда на самом деле происходит с элементами массива, под какую категорию они подпадают? Ау, Рихтер, где ты?  smile 

Автор: Void 11.7.2007, 22:03
Цитата(mr.DUDA @  11.7.2007,  23:32 Найти цитируемый пост)
Вопрос 2: как GC рассматривает объекты, созданные на стеке но хранимые в массиве?

Это как?

Автор: mr.DUDA 11.7.2007, 22:10
Цитата(Void @ 11.7.2007,  22:03)
Цитата(mr.DUDA @  11.7.2007,  23:32 Найти цитируемый пост)
Вопрос 2: как GC рассматривает объекты, созданные на стеке но хранимые в массиве?

Это как?

Это так:
Код
int[] array = new int[10];


Что есть элемент массива array? Это value type (и тогда он физически расположен на стеке) или reference type (лежит в куче) ?

Автор: Azzdorf 11.7.2007, 22:14
Насколько ефективно использовать GC???? Я знаю что в некоторых языках нужно было самому выделять стеки и после выполнения разных действий удалять их - не есть ли этот способ - лучшим в организации выделения памяти под работу компютера - если д, то на...GC???? smile  smile  smile 
Или он придумал для сокращения процеса разработки програмного обеспичения???

Автор: tol05 11.7.2007, 22:27
Цитата(mr.DUDA @  11.7.2007,  21:32 Найти цитируемый пост)
Противоречие: стек чистится = вся память занятая под стек очищается = все объекты выделенные на стековой памяти удаляются

нет противоречия если мы в ф-ции создаем массив целых чисел
Код

int[] arrInt = new int[10]  //кстати, оператор new - это ведь вызов dynamicalloc ? :)
то в стеке создается переменная 32 бита для хранения значени переменной arrInt. А значением этой переменной будет адрес блока памяти, выделенного под массив (под десять целых чисел + системмные блоки класса)
После выхода из ф-ции переменная arrInt сотрется, а блок памяти для массива в куче - останется.

Ответ 1  
Цитата(mr.DUDA @  11.7.2007,  21:32 Найти цитируемый пост)
 куда при этом деваются объекты (структуры, инты и т.п.) хранимые в массиве?

smile эти объекты размещаются в куче изначально, в ней и хранятся, уничтожаются сборщиком мусора. Поэтому "они остаются жить после очистки стековой памяти". Все то же самое, как в случае с массивом arrInt... Еще раз повторю:в стеке хранится (и после выхода из ф-ции удаляется) только ссылка на массив! 
Если структура, инт и что угодно из value-объектов создаются сами по себе, то они размещаются и хранятся в стеке, благо посчитать требуемый ими объем памяти - несложно. Если они - члены ссылочного типа, то размещаться они будут в куче, в блоке памяти, выделенном под ссылочный объект. Если у структуры есть поле ссылочного типа, то в стеке будет размещена вся структура (под член ссылочного типа будет выделено 4 байта, для хранения ссылки на кучу). Когда стек будет очищаться - в куче останется недостижимый объект (бывший член структуры)

Ответ 2 
Цитата(mr.DUDA @  11.7.2007,  21:32 Найти цитируемый пост)
 как GC рассматривает объекты, созданные на стеке но хранимые в массиве
 честно говоря не понял, что ты имеешь в виду... 
Цитата(mr.DUDA @  11.7.2007,  21:32 Найти цитируемый пост)
попадают ли они в поколения, собираемые GC?
 в поколения может попасть все, что подвластно сборщику мусора, т.е. все, что хранится в куче. А попадет реально, или нет - это уже у GC спрашивать нужно. smile Но если тип поддерживает финализатор - 100% попадет.

Ответ 3 (на "З.Ы.")
Мне кажется, что ты зря связываешь понятия поколения с боксингом, + еще куча со стеком... smile
Главное - это к какому типу ссылочного объекта принадлежат простейшие. Ну и от системмных условий. От этого зависит как часто и насколько тщательно будет сборщик мусора собирать мусор. А боксинг используется только при приведении типов. Конечно, и массивы и генерики - типизированы, поэтому они не нуждаются в боксинге.
Но это не важно для нашего вопроса: незабоксенные инты (члены массива) будут находится в куче также, как забоксенные, как вообще все элементы ссылочных типов.... И когда GC рещит "грохнуть" объект в куче, он "грохнет" его вместе со всеми его членами, даже если там 10 незабоксенных и 5 забоксенных.

Azzdorf вопрос непосредственного использования GC - зависит от ситуации. Но "по статистике"  smile применяется очень редко... Гораздо реже IDisposable. Вот это действительно, на что нужно обратить внимание в первую очередь...

Динамическое выделение стековой памяти, стековые массивы - это оптимизация производительности прежде всего. Тоже - непростая и спорная тема... smile

Автор: Void 11.7.2007, 22:28
Кто и когда говорил, что экземпляры value types всегда хранятся в стеке?
Цитата(Рихтер @  CLR via C#)
Экземпляры этих [значимых] типов обычно размещаются в стеке потока (хотя они могут быть встроены и в объект ссылочного типа).

В случае с массивом имеет место как раз второй вариант.

mr.DUDA, уж не завладел ли кто твоим аккаунтом, если ты такие вещи спрашиваешь? smile

Цитата(Azzdorf @  12.7.2007,  00:14 Найти цитируемый пост)
Я знаю что в некоторых языках нужно было самому выделять стеки и после выполнения разных действий удалять их - не есть ли этот способ - лучшим в организации выделения памяти под работу компютера - если д, то на...GC????

С пулами объектов есть серьёзные проблемы. С region inference тоже.

Автор: mr.DUDA 11.7.2007, 22:38
Цитата(Void @  11.7.2007,  22:28 Найти цитируемый пост)
В случае с массивом имеет место как раз второй вариант

.mr.DUDA, уж не завладел ли кто твоим аккаунтом, если ты такие вещи спрашиваешь?

Да нет. Просто начав оптимизировать одну софтину, активно создающую тонны мелких объектов, пришёл к тому что можно объявить их структурами и хранить в пуле (а-ля массив с запасом), и тут посетила мысль: а как к этому массиву отнесётся GC? После чего экстраполировал мысль на все остальные случаи. Просто непонятно, что это за тип такой "массив", что сам он является ссылочным типом - не копируется при присвоении, собирается при уборке -- но элементы массива не являются ссылочными типами.

Это, имхо, либо ломает общую организацию работы с памятью в .NET, либо вводит исключение из правила.

Автор: Azzdorf 11.7.2007, 22:40
Цитата

tol05Динамическое выделение стековой памяти, стековые массивы - это оптимизация производительности прежде всего. Тоже - непростая и спорная тема...



согласен что спорная, но не есть ли оптимальная робота программы с памятю - одним из столпов професионального программирования и создания ефективных преложений????  и стоит ли к этому стремится или это пустая трата времени???

Автор: tol05 11.7.2007, 22:53
Цитата(Azzdorf @  11.7.2007,  22:40 Найти цитируемый пост)
 но не есть ли оптимальная робота программы с памятю - одним из столпов професионального программирования и создания ефективных преложений????  и стоит ли к этому стремится или это пустая трата времени???
я не говорил, что это не нужно или плохо smile Стремится надо? Значит будем  smile 

просто это - новый виток в бесконечной теме оптимизации ресурсов и производительности. Тут несколько типоков создать прийдется smile

mr.DUDA, массив - это класс. Вот и все. Классы тоже " не копируется при присвоении, собирается при уборке" и элементами классов тоже могут быть не ссылочные типы.
Точно так же, как элементами массива могут быть как ссылочные, так и типы по-значению.

Я бы сказал, что массив - просто про-про-паттерн  smile 


Автор: ivashkanet 12.7.2007, 09:45
Давайте и я своих 5 копеек...


Почему никто не вспоминает про такие операции как запаковка и распаковка?
Именно таким образом значимые типы хранятся в куче. Т.е. у каждого Value-типа есть брат билзнец, который является ссылочным типом и храниться в куче.

Все остальное мои мысли и не могут считаться полностью достоверными.

Когда происходит эта распаковки и запаковка? А когда нужно что-то сделать со "значением", что не соответствует его типу, например:
Код

int i =0; // ссылка
i++; // Еще ссылка
Console.Write(i.ToString()) // Уже не ссылка (запаковка)

int j = i; // Скорее всего i опять стала ссылкой (распаковка), но кто ее знает :)


По поводу массивов. Лопатил как-то MSDN и набрел на такую штуку:
Цитата(http://msdn2.microsoft.com/en-us/library/6sh2ey19.aspx)

Performance Considerations

In deciding whether to use the List or ArrayList class, both of which have similar functionality, remember that the List class performs better in most cases and is type safe. If a reference type is used for type T of the List class, the behavior of the two classes is identical. However, if a value type is used for type T, you need to consider implementation and boxing issues.

If a value type is used for type T, the compiler generates an implementation of the List class specifically for that value type. That means a list element of a List object does not have to be boxed before the element can be used, and after about 500 list elements are created the memory saved not boxing list elements is greater than the memory used to generate the class implementation.

Make certain the value type used for type T implements the IEquatable generic interface. If not, methods such as Contains must call the Object.Equals method, which boxes the affected list element. If the value type implements the IComparable interface and you own the source code, also implement the IComparable generic interface to prevent the BinarySearch and Sort methods from boxing list elements. If you do not own the source code, pass an IComparer object to the BinarySearch and Sort methods


Т.е. List<T> where T:ValueType пытается храниться в стеке до тех пор пока его не станут использовать как класс (вызывать его методы, например. Хотя, судя по цитате, при вызове методов не всегда происходит запаковка) либо до тех пор пока его не целесообразнее положить в кучу.
Что-то похожее должно быть и про простой массив, но в MSDN я этого не нашел :(

Цитата(mr.DUDA @  11.7.2007,  22:38 Найти цитируемый пост)
Просто начав оптимизировать одну софтину, активно создающую тонны мелких объектов, пришёл к тому что можно объявить их структурами и хранить в пул

ИМХО, пул и структуры вещи совершенно несовместимые. Ибо при присваивании структуры создается новая копия.
Вот пул классов -- это да.

Автор: mr.DUDA 12.7.2007, 09:56
Цитата(ivashkanet @  12.7.2007,  09:45 Найти цитируемый пост)
ИМХО, пул и структуры вещи совершенно несовместимые. Ибо при присваивании структуры создается новая копия.

Оффтопик. Но отвечу. Для того чтобы не копировало, юзается ref при передаче через аргументы метода. Во всех остальных случаях юзается через массив по индексу (т.е. без копирования в локальную переменную).

Насчёт боксинга ты правильно заметил. Вот только вопрос про то почему стековая память называется такой, ею не являясь, остаётся открытым.

Автор: ivashkanet 12.7.2007, 10:06
Цитата(mr.DUDA @  12.7.2007,  09:56 Найти цитируемый пост)
Оффтопик. Но отвечу. Для того чтобы не копировало, юзается ref при передаче через аргументы метода. Во всех остальных случаях юзается через массив по индексу (т.е. без копирования в локальную переменную).

Тогда да, но что-то через одно место получается как-то. Ее же, ИМХО, никак нельзя использовать вне массива (ни для каких вычислений). Ну да ладно 

Автор: tol05 12.7.2007, 10:08
mr.DUDA, с чего ты взял, что 
Цитата(mr.DUDA @  12.7.2007,  09:56 Найти цитируемый пост)
стековая память называется такой, ею не являясь
не мгу понять. Стековая память - это память, заполняемая при входе в функцию значениями и очищаемая после выхода из ф-ции.
Она при входе в ф-цию заполнилась value-типами и ссылками на reference-типы. При выходе из ф-ции она очистилась - value-типы и ссылки на reference-типы уничтожились. Сами reference-типы еще остались в куче, до сборки мусора.
Что не так?

Массив - это класс. Члены массива хранятся в куче. Ссылка на массив хранится в стеке.

Автор: mr.DUDA 12.7.2007, 10:14
Цитата(tol05 @  12.7.2007,  10:08 Найти цитируемый пост)
Члены массива хранятся в куче. Ссылка на массив хранится в стеке.

Вообще запутал. Тут же себе противоречишь:

Цитата(tol05 @  12.7.2007,  10:08 Найти цитируемый пост)
Стековая память - это память, заполняемая при входе в функцию значениями и очищаемая после выхода из ф-ции.

Получается, ссылка на массив уничтожится при выходе из функции, раз она "хранится в стеке". Хотя даже если и наоборот (ссылка - в куче, элементы - в стеке), всё равно не вкуриваю, где на самом деле хранятся элементы массива. 
1. Если они не уничтожаются при выходе из метода - значит, вероятно не в стеке
2. Если они не боксятся и остаются нормальными value type (например int-ы), значит не в куче.

Или всё-таки в куче можно хранить value-type объекты без боксинга? Или массивы - специальный тип, как я предполагаю?

З.Ы
ivashkanet, если интересно могу прислать образец кода. Кстати, мелкомягкие в XNA вовсю юзают структуры, а чтобы не копировалось лишний раз зря - повсеместно юзают модификатор ref.

Автор: ivashkanet 12.7.2007, 10:17
Цитата(mr.DUDA @  12.7.2007,  09:56 Найти цитируемый пост)
Вот только вопрос про то почему стековая память называется такой, ею не являясь, остаётся открытым. 

А что такое Стек, когда у нас есть только оперативная память?
Конечно это обычная оперативная память, только она специально организована. И, ИМХО, выигрыш идет не на порядок, а раза в два-три (ИМХО), так как в случае стека мы вигрываем из-за отстутствия сборок мусора и более простому доступу (адреса переменных в стеке должы быть поменьше), но проигрываем из-за этой "организованности" стека.

P.S. Про регистры и кэши процессора лучше не упоминать, так как процессы часто ожидают своей очереди у процессора, а в это время весь их контекст храниться в оперативке.

P.P.S. 
Цитата(tol05 @  12.7.2007,  10:08 Найти цитируемый пост)
Массив - это класс. Члены массива хранятся в куче. Ссылка на массив хранится в стеке.

Почитай мой пост про List<T> where T:ValueType

Добавлено через 14 минут и 49 секунд
Цитата(mr.DUDA @  12.7.2007,  10:14 Найти цитируемый пост)
ivashkanet, если интересно могу прислать образец кода. Кстати, мелкомягкие в XNA вовсю юзают структуры, а чтобы не копировалось лишний раз зря - повсеместно юзают модификатор ref. 

Не пасиб. Не нуна  smile 
Цитата(mr.DUDA @  12.7.2007,  10:14 Найти цитируемый пост)
Получается, ссылка на массив уничтожится при выходе из функции, раз она "хранится в стеке". Хотя даже если и наоборот (ссылка - в куче, элементы - в стеке), всё равно не вкуриваю, где на самом деле хранятся элементы массива. 

Не, все нормуль. Это нормальное поведение ссылочного типа: все ссылки на него теряются, а он все еще жив, но не долго -- до первой сборки мусора.

Только вот, судя по MSDN, небольшиуе массивы хранятся в стеке  smile 

Автор: ivashkanet 12.7.2007, 10:33
Цитата(mr.DUDA @  12.7.2007,  10:14 Найти цитируемый пост)
ivashkanet, если интересно могу прислать образец кода.

А хотя, пришли, плиз. Я хочу посмотреть. Только потрать немножко времени, выдели самое главное, пожайлуйста

Автор: tol05 12.7.2007, 10:35
mr.DUDA, я видел, ты иногда бросаешь ссылки на книгу "C#2005 для профессионалов". Открой стр. 102 
Цитата

Все массивы - ссылочные типы и следуют семантике ссылок....


Я нигде не противоречил smile Я сейчас распишу свою фразу подробно. Без обид, просто это уже просто усталось сказывается, восприятие понизилось, у меня такое постоянно smile

Массив - это класс. Члены массива хранятся в куче. Ссылка на массив хранится в стеке.
Стековая память - это память, заполняемая при входе в функцию значениями и очищаемая после выхода из ф-ции.
Она при входе в ф-цию заполнилась value-типами и ссылками на reference-типы (в том числе и ссылкой на массив - переменная arrInt является ссылкой на массив, члены которого хранятся в куче). При выходе из ф-ции она очистилась - value-типы и ссылки на reference-типы уничтожились (в том числе, ячейка, хранящая адрес массива и называющаяся переменной arrInt). Сами reference-типы еще остались в куче, до сборки мусора (все ячейки, содержащие реальные значения элементов массива arrInt).


Цитата(mr.DUDA @  12.7.2007,  10:14 Найти цитируемый пост)
Если они не уничтожаются при выходе из метода - значит, вероятно не в стеке

конечно они не в стеке. Они в куче, а вот указатель на них (область памяти, выделенную для хранения их всех) - он как раз в стеке


Цитата(mr.DUDA @  12.7.2007,  10:14 Найти цитируемый пост)
Если они не боксятся и остаются нормальными value type (например int-ы), значит не в куче

Я предлагаю вообще никому про боксинг не упоминать. Это только путает. 
Боксинг для того, чтобы число передать в виде объекта кому-нибудь. И все. Допустим число создано внутри метода. Оно хранится в стеке. Вызываем метод MyFunc(object o) или Console.Write(object o). Мы можем передать наше число, которое счас в стеке. Но компилятор упакует его в object - т.е. создаст в куче объект (с возможностями типа object), инициализирует его числом и передаст в метод. В стеке наше число останется. В куче новый объект появится. То же самое будет в случае, когда приводим число к объекту явно...
Закончили работу - стек с числом очистился, оникому уже не нужный объект в куче остался.
Лучше про боксинг пока не упоминать... Это НЕ ОТНОСИТСЯ к методам работы стека и кучи. Это работа компилятора для согласования типов данных.

Код пришли и мне, плиз.

ivashkanet дай плиз ссылку на место, где упоминается про "небольшиуе массивы хранятся в стеке  " просто я слышал, что создавать стековые массивы нужно специально. (тоже в той книжке. что упоминал, там, где указатели описываются) Может в 3.0 появилось?

Автор: ivashkanet 12.7.2007, 10:46
Цитата(tol05 @  12.7.2007,  10:35 Найти цитируемый пост)
"небольшиуе массивы хранятся в стеке  "

Нет, про массивы я все же не видел. Только про List<T>. Но он же сделан на основе масссива...

Добавлено через 6 минут и 5 секунд
Цитата(tol05 @  12.7.2007,  10:35 Найти цитируемый пост)
просто я слышал, что создавать стековые массивы нужно специально

А я о таком даже не слышал. Можно мне ссылку

Автор: mr.DUDA 12.7.2007, 12:08
Цитата(tol05 @  12.7.2007,  10:35 Найти цитируемый пост)
Сами reference-типы еще остались в куче, до сборки мусора (все ячейки, содержащие реальные значения элементов массива arrInt).


Цитата(tol05 @  12.7.2007,  10:35 Найти цитируемый пост)
конечно они не в стеке. Они в куче,


Ага, наконец-то я услышал что хотел: элементы массива хранятся в куче!
Вот это и сбивает с толку. Как это value-type может в куче быть. Наверно, надо Рихтера всё-таки почитать smile 

З.Ы. Пример с пулом структур:

Предположим, есть у нас некая структура данных с размером этак 100..200 байт. Таких классов или структур (назовём её Particle, хотя название и назначение не суть важно), может понадобиться создавать много. Ну к примеру, иметь 10000 экземпляров одновременно. Варианты как делать это:

1. Объявить классом и создавать с пом. new по необходимости; хранить где угодно - в List<> например. Неэффективно ввиду GC, особенно если объекты хранятся долго и попадают в 1-е а то и 2-е поколение сборки мусора
2. Объявить структурой и также создавать с пом. new, хранить в массиве или List<> или др. типизированной коллекции. Этот вариант лучше чем №1 ввиду того что юзаем непрерывные массивы, состоящие из структур (List<> тоже массив юзает), никакого боксинга и никаких затрат на GC. Поясняю: массив структур во время сборки мусора рассматривается как 1 объект. Недостатки всё же есть: 
- если юзать массив, теряем возможность добавления/удаления элементов
- если юзать List или другую коллекцию, получаем затраты на удаление элемента - в List.RemoveAt весь хвост сдвигается вверх с пом. Array.Copy()
- в случае доступа по индексу List возвращает копию а не экземпляр структуры, о чём говорил ivashkanet; это лишние затраты которых желательно избегать в случае "толстых" структур (более 4 байт)
3. Наконец, вариант с пулом структур. Остановлюсь подробнее на этом.

Под простейшим пулом структур в моём понятии подразумевается коллекция, аналогичная List<>, позволяющая добавлять, удалять элементы и проходить по ним в цикле. Внутри себя это обычный массив структур, обёрнутый парой методов - Alloc, Remove(i) и выставляющий тот самый массив как public-поле. Вот примеры кода:

Код
using System;

class Pool<T> where T : struct
{
    public T[] Arr = new T[0];
    public int Count = 0;

    /// <summary>Выделяет элемент в пуле</summary>
    /// <returns>Индекс нового элемента</returns>
    public int Alloc()
    {
        return Alloc(1);
    }

    /// <summary>Выделяет заданное количество элементов в пуле</summary>
    public int Alloc(int amount)
    {
        Count += amount;
        if (Count > Arr.Length)
            Array.Resize(ref Arr, (Count * 4) / 3); // с запасом
        return Count - 1;
    }

    /// <summary>Освобождает элемент пула</summary>
    /// <param name="i">Индекс удаляемого элемента</param>
    public void RemoveAt(int i)
    {
        if (i < 0 || i >= Count) return;

        Count--;
        if (i != Count && Count > 0)
        {
            // если удаляем из середины, копируем элемент из хвоста в освободившуюся позицию
            Arr[i] = Arr[Count];
        }
    }
}

struct Particle
{
    public int A, B, C;
    public float D, E, F;
}

class Program
{
    // вымышленный метод "инициализирующий" элемент пула
    void InitParticle(ref Particle particle)
    {
        particle.A = particle.B = particle.C = 1;
        particle.D = 2; particle.E = 3; particle.F = 4;
    }

    // ещё один вымышленный метод, "обрабатывающий" элемент
    void ProcessParticle(ref Particle particle)
    {
        particle.A = particle.B * particle.C;
        particle.E = 1; particle.F += 10;
        particle.D += particle.E * particle.F;
    }

    void Test()
    {
        Pool<Particle> pool = new Pool<Particle>();
        pool.Alloc(1000);

        for (int i = 0; i < pool.Count; i++)
            InitParticle(ref pool.Arr[i]);

        pool.RemoveAt(100);

        for (int i = 0; i < pool.Count; i++)
            ProcessParticle(ref pool.Arr[i]);

    }


    static void Main()
    {
        new Program().Test();
    } 
}


З.Ы.Ы. за нарушение принципов ООП не ругать! Я о них знаю  smile. Есть такие случаи, где выгоднее нарушить инкапсуляцию, чем потерять в производительности.

Добавлено через 41 секунду
ivashkanet, 
Цитата(ivashkanet @  12.7.2007,  10:46 Найти цитируемый пост)
просто я слышал, что создавать стековые массивы нужно специально

А я о таком даже не слышал. Можно мне ссылку

См. оператор stackalloc, но он возвращает указатель а не массив, и требует unsafe.

Автор: tol05 12.7.2007, 12:24
может и офф-топик. но все же...
Цитата(mr.DUDA @  12.7.2007,  12:08 Найти цитируемый пост)
Вот это и сбивает с толку. Как это value-type может в куче быть.

А что тогда вообще в куче может быть, по-твоему?  smile 
Класс, у которого два поля и оба int. Он в куче. А его два поля где? тоже в куче. В куче выделено два блока памяти для хранения двух int
Так же и массив. int[10] - в куче выделен блок памяти для хранения десяти int

Спасибо за код. Я посмотрю, но комментировать не буду. Просто интересный вариант, со своим правом на существование ... smile


ivashkanet, ссылка - "С# 2005 для профессионалов", 
Цитата(tol05 @  12.7.2007,  10:35 Найти цитируемый пост)
там, где указатели описываются
  smile 

Автор: Azzdorf 12.7.2007, 17:33
ок простой вопрос smile , до ужаса smile 
когда мы жмем три чудесные кнопочки и запускаем в Винде (да будет проклят Билл) в диспечере задач --> закладку Процессы
там есть колонки: Память и Вирувальная память

Вопрсы: Какая-то из них показывает размер Кучи или Стека или это что-то не то?????? smile 
 smile Какими средствами можна их посмотрть??? smile 
И ефективно ли запускать GC после нагруженых методов и функций??? smile 

Автор: tol05 12.7.2007, 17:48
Данные для 32-битной Windows
размер стека:
  по умолчанию под стек каждого потока выделяется 1МБайт памяти. (это для "юзания" программой, не учитывает объемы системмных областей)
размер кучи:
  по умолчанию для каждого процесса выделяется 4Гбайт виртуальной памяти.
Цитата(Azzdorf @  12.7.2007,  17:33 Найти цитируемый пост)
Какими средствами можна их посмотрть

Профайлерами, если не ошибаюсь.

То, что ты видишь в диспечере задач - это используемый сейчас объем памяти

Цитата(Azzdorf @  12.7.2007,  17:33 Найти цитируемый пост)
ефективно ли запускать GC после нагруженых методов и функций??? 

Да, эффективно. Именно поэтому в public интерфейс и выведены члены класса GC, чтобы с ними работать smile

Автор: Azzdorf 12.7.2007, 18:05
Цитата(tol05 @ 12.7.2007,  17:48)
То, что ты видишь в диспечере задач - это используемый сейчас объем памяти

физической или оперативной???

Добавлено через 2 минуты
если оперативной то тогда почему моя маленькая простая прога ест 48метров, когда тотже запищеный файл ворда - 10метров???

Автор: tol05 12.7.2007, 18:31
 smile 
Azzdorf, воспользуйся поиском, Рихтера почитай (он не только по .Net пишет, в основном - по работе Windows)
http://wm-help.net/books-online/book/59464/59464-9.html

Память... есть внутренняя память процессора, ОЗУ, файлы подкачки. Процессоры разные, платформы...

я не могу точно ответить тебе на вопрос. Про .Net - это да, постараюсь, но это ИМХО больше вопросы к сис.админам....


Автор: Naum 12.7.2007, 18:46
Цитата(Azzdorf @  12.7.2007,  18:33 Найти цитируемый пост)
Память и Вирувальная память

Память - это собсна оперативная память. Ее размер зависит от того, сколько и каких плат ты воткнул в материнскую плату.
Виртуальная память - это, в принципе, тоже оперативная память. Но правильнее "оперативная", потому как все ее содержимое хранится на жестком диске. (Слышал про файл подкачки?)
Цитата(Azzdorf @  12.7.2007,  19:05 Найти цитируемый пост)
моя маленькая простая прога ест 48метров, когда тотже запищеный файл ворда - 10метров

Это уже не недостаток GC, это уже недостаток всего дотнета.

Автор: mr.DUDA 12.7.2007, 20:00
Цитата(Azzdorf @  12.7.2007,  18:05 Найти цитируемый пост)
если оперативной то тогда почему моя маленькая простая прога ест 48метров, когда тотже запищеный файл ворда - 10метров???

Потому что дотнет жадный до памяти. Во-первых, JIT-скомпилированный код много занимает, а во-вторых, память изначально выделяется со здоровым запасом.

Автор: Azzdorf 13.7.2007, 14:08
Цитата(Naum @ 12.7.2007,  18:46)
Память - это собсна оперативная память. Ее размер зависит от того, сколько и каких плат ты воткнул в материнскую плату.
Виртуальная память - это, в принципе, тоже оперативная память. Но правильнее "оперативная", потому как все ее содержимое хранится на жестком диске. (Слышал про файл подкачки?)

Я вполне знаю что такое оперативка и файл подкачки - просто было интересно что имеено там отображаеться.

Всем спасибо, узнал многое, будем читать литературу... Топик закрываю..

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)