| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Общие вопросы по .NET и C# > Garbage Collector |
| Автор: Azzdorf 11.7.2007, 14:31 |
| Тут вопросик общего плана. Программа создает Кучу и Стек. Куча умерает ли вместе с программой???? А GAC чистит только стек???? И каким методом можна автоматически запускать Garbige Collector в нужный момент времени... |
| Автор: QryStaL 11.7.2007, 16:19 | ||
|
| Автор: ivashkanet 11.7.2007, 17:08 |
Конечно. Об этом заботиться среда .Net Нет, только кучу Стек вообще никто не чистит специально. Он так устроен, что чиститься автоматически и задумываться об его очистке не надо |
| Автор: Azzdorf 11.7.2007, 20:41 | ||
А что там чистить в Куче и Что GAC чистит в стеке???? |
| Автор: mr.DUDA 11.7.2007, 20:48 |
| Стек - вообще интересное понятие. Вот кто например может мне сказать, почему массивы хранятся вне памяти метода (т.е. в куче), однако элементы массива являются value type? Это что, означает что есть некая память называемая стековой, но таковой не являющаяся? |
| Автор: Azzdorf 11.7.2007, 21:05 | ||||||
Добавлено через 1 минуту и 5 секунд
он сам пройдется, освободит файл и вырубиться7??? |
| Автор: mr.DUDA 11.7.2007, 21:32 | ||||
Противоречие: стек чистится = вся память занятая под стек очищается = все объекты выделенные на стековой памяти удаляются Вопрос 1: куда при этом деваются объекты (структуры, инты и т.п.) хранимые в массиве? Они ведь value type а не reference type, и в отличие от массива должны быть выделены на стеке. Почему же они остаются жить после очистки стековой памяти? Вопрос 2: как GC рассматривает объекты, созданные на стеке но хранимые в массиве? Как часть reference-типа? То есть попадают ли они в поколения, собираемые GC? З.Ы. Судя по тому что я видел в .NET Memory Profiler, даже простейшие int-ы собираются GC вплоть до 1-2 поколений сборки мусора. Но это объяснимо в случае если они боксятся. В случае же массивов, как и generic-ов заявляемые мелкософтом возможности гарантируют что простейшие типы не будут бокситься, если они лежат в массиве или одной из generic-коллекций (кстати, все generic-коллекции так или иначе юзают массивы). Что же тогда на самом деле происходит с элементами массива, под какую категорию они подпадают? Ау, Рихтер, где ты? |
| Автор: Void 11.7.2007, 22:03 | ||
Это как? |
| Автор: mr.DUDA 11.7.2007, 22:10 | ||||||
Это так:
Что есть элемент массива array? Это value type (и тогда он физически расположен на стеке) или reference type (лежит в куче) ? |
| Автор: Azzdorf 11.7.2007, 22:14 |
| Насколько ефективно использовать GC???? Я знаю что в некоторых языках нужно было самому выделять стеки и после выполнения разных действий удалять их - не есть ли этот способ - лучшим в организации выделения памяти под работу компютера - если д, то на...GC???? Или он придумал для сокращения процеса разработки програмного обеспичения??? |
| Автор: tol05 11.7.2007, 22:27 | ||||||||
нет противоречия если мы в ф-ции создаем массив целых чисел
После выхода из ф-ции переменная arrInt сотрется, а блок памяти для массива в куче - останется. Ответ 1
Если структура, инт и что угодно из value-объектов создаются сами по себе, то они размещаются и хранятся в стеке, благо посчитать требуемый ими объем памяти - несложно. Если они - члены ссылочного типа, то размещаться они будут в куче, в блоке памяти, выделенном под ссылочный объект. Если у структуры есть поле ссылочного типа, то в стеке будет размещена вся структура (под член ссылочного типа будет выделено 4 байта, для хранения ссылки на кучу). Когда стек будет очищаться - в куче останется недостижимый объект (бывший член структуры) Ответ 2
в поколения может попасть все, что подвластно сборщику мусора, т.е. все, что хранится в куче. А попадет реально, или нет - это уже у GC спрашивать нужно. Ответ 3 (на "З.Ы.") Мне кажется, что ты зря связываешь понятия поколения с боксингом, + еще куча со стеком... Главное - это к какому типу ссылочного объекта принадлежат простейшие. Ну и от системмных условий. От этого зависит как часто и насколько тщательно будет сборщик мусора собирать мусор. А боксинг используется только при приведении типов. Конечно, и массивы и генерики - типизированы, поэтому они не нуждаются в боксинге. Но это не важно для нашего вопроса: незабоксенные инты (члены массива) будут находится в куче также, как забоксенные, как вообще все элементы ссылочных типов.... И когда GC рещит "грохнуть" объект в куче, он "грохнет" его вместе со всеми его членами, даже если там 10 незабоксенных и 5 забоксенных. Azzdorf вопрос непосредственного использования GC - зависит от ситуации. Но "по статистике" Динамическое выделение стековой памяти, стековые массивы - это оптимизация производительности прежде всего. Тоже - непростая и спорная тема... |
| Автор: Void 11.7.2007, 22:28 | ||||
Кто и когда говорил, что экземпляры value types всегда хранятся в стеке?
В случае с массивом имеет место как раз второй вариант. mr.DUDA, уж не завладел ли кто твоим аккаунтом, если ты такие вещи спрашиваешь?
С пулами объектов есть серьёзные проблемы. С region inference тоже. |
| Автор: mr.DUDA 11.7.2007, 22:38 | ||
Да нет. Просто начав оптимизировать одну софтину, активно создающую тонны мелких объектов, пришёл к тому что можно объявить их структурами и хранить в пуле (а-ля массив с запасом), и тут посетила мысль: а как к этому массиву отнесётся GC? После чего экстраполировал мысль на все остальные случаи. Просто непонятно, что это за тип такой "массив", что сам он является ссылочным типом - не копируется при присвоении, собирается при уборке -- но элементы массива не являются ссылочными типами. Это, имхо, либо ломает общую организацию работы с памятью в .NET, либо вводит исключение из правила. |
| Автор: Azzdorf 11.7.2007, 22:40 | ||
согласен что спорная, но не есть ли оптимальная робота программы с памятю - одним из столпов професионального программирования и создания ефективных преложений???? и стоит ли к этому стремится или это пустая трата времени??? |
| Автор: tol05 11.7.2007, 22:53 | ||
просто это - новый виток в бесконечной теме оптимизации ресурсов и производительности. Тут несколько типоков создать прийдется mr.DUDA, массив - это класс. Вот и все. Классы тоже " не копируется при присвоении, собирается при уборке" и элементами классов тоже могут быть не ссылочные типы. Точно так же, как элементами массива могут быть как ссылочные, так и типы по-значению. Я бы сказал, что массив - просто про-про-паттерн |
| Автор: ivashkanet 12.7.2007, 09:45 | ||||||
| Давайте и я своих 5 копеек... Почему никто не вспоминает про такие операции как запаковка и распаковка? Именно таким образом значимые типы хранятся в куче. Т.е. у каждого Value-типа есть брат билзнец, который является ссылочным типом и храниться в куче. Все остальное мои мысли и не могут считаться полностью достоверными. Когда происходит эта распаковки и запаковка? А когда нужно что-то сделать со "значением", что не соответствует его типу, например:
По поводу массивов. Лопатил как-то MSDN и набрел на такую штуку:
Т.е. List<T> where T:ValueType пытается храниться в стеке до тех пор пока его не станут использовать как класс (вызывать его методы, например. Хотя, судя по цитате, при вызове методов не всегда происходит запаковка) либо до тех пор пока его не целесообразнее положить в кучу. Что-то похожее должно быть и про простой массив, но в MSDN я этого не нашел :(
ИМХО, пул и структуры вещи совершенно несовместимые. Ибо при присваивании структуры создается новая копия. Вот пул классов -- это да. |
| Автор: mr.DUDA 12.7.2007, 09:56 | ||
Оффтопик. Но отвечу. Для того чтобы не копировало, юзается ref при передаче через аргументы метода. Во всех остальных случаях юзается через массив по индексу (т.е. без копирования в локальную переменную). Насчёт боксинга ты правильно заметил. Вот только вопрос про то почему стековая память называется такой, ею не являясь, остаётся открытым. |
| Автор: ivashkanet 12.7.2007, 10:06 | ||
Тогда да, но что-то через одно место получается как-то. Ее же, ИМХО, никак нельзя использовать вне массива (ни для каких вычислений). Ну да ладно |
| Автор: tol05 12.7.2007, 10:08 |
| mr.DUDA, с чего ты взял, что не мгу понять. Стековая память - это память, заполняемая при входе в функцию значениями и очищаемая после выхода из ф-ции. Она при входе в ф-цию заполнилась value-типами и ссылками на reference-типы. При выходе из ф-ции она очистилась - value-типы и ссылки на reference-типы уничтожились. Сами reference-типы еще остались в куче, до сборки мусора. Что не так? Массив - это класс. Члены массива хранятся в куче. Ссылка на массив хранится в стеке. |
| Автор: mr.DUDA 12.7.2007, 10:14 | ||
Вообще запутал. Тут же себе противоречишь:
Получается, ссылка на массив уничтожится при выходе из функции, раз она "хранится в стеке". Хотя даже если и наоборот (ссылка - в куче, элементы - в стеке), всё равно не вкуриваю, где на самом деле хранятся элементы массива. 1. Если они не уничтожаются при выходе из метода - значит, вероятно не в стеке 2. Если они не боксятся и остаются нормальными value type (например int-ы), значит не в куче. Или всё-таки в куче можно хранить value-type объекты без боксинга? Или массивы - специальный тип, как я предполагаю? З.Ы ivashkanet, если интересно могу прислать образец кода. Кстати, мелкомягкие в XNA вовсю юзают структуры, а чтобы не копировалось лишний раз зря - повсеместно юзают модификатор ref. |
| Автор: ivashkanet 12.7.2007, 10:17 | ||||||||
А что такое Стек, когда у нас есть только оперативная память? Конечно это обычная оперативная память, только она специально организована. И, ИМХО, выигрыш идет не на порядок, а раза в два-три (ИМХО), так как в случае стека мы вигрываем из-за отстутствия сборок мусора и более простому доступу (адреса переменных в стеке должы быть поменьше), но проигрываем из-за этой "организованности" стека. P.S. Про регистры и кэши процессора лучше не упоминать, так как процессы часто ожидают своей очереди у процессора, а в это время весь их контекст храниться в оперативке. P.P.S.
Почитай мой пост про List<T> where T:ValueType Добавлено через 14 минут и 49 секунд
Не пасиб. Не нуна
Не, все нормуль. Это нормальное поведение ссылочного типа: все ссылки на него теряются, а он все еще жив, но не долго -- до первой сборки мусора. Только вот, судя по MSDN, небольшиуе массивы хранятся в стеке |
| Автор: ivashkanet 12.7.2007, 10:33 |
А хотя, пришли, плиз. Я хочу посмотреть. Только потрать немножко времени, выдели самое главное, пожайлуйста |
| Автор: tol05 12.7.2007, 10:35 | ||||||
mr.DUDA, я видел, ты иногда бросаешь ссылки на книгу "C#2005 для профессионалов". Открой стр. 102
Я нигде не противоречил Массив - это класс. Члены массива хранятся в куче. Ссылка на массив хранится в стеке. Стековая память - это память, заполняемая при входе в функцию значениями и очищаемая после выхода из ф-ции. Она при входе в ф-цию заполнилась value-типами и ссылками на reference-типы (в том числе и ссылкой на массив - переменная arrInt является ссылкой на массив, члены которого хранятся в куче). При выходе из ф-ции она очистилась - value-типы и ссылки на reference-типы уничтожились (в том числе, ячейка, хранящая адрес массива и называющаяся переменной arrInt). Сами reference-типы еще остались в куче, до сборки мусора (все ячейки, содержащие реальные значения элементов массива arrInt).
конечно они не в стеке. Они в куче, а вот указатель на них (область памяти, выделенную для хранения их всех) - он как раз в стеке
Я предлагаю вообще никому про боксинг не упоминать. Это только путает. Боксинг для того, чтобы число передать в виде объекта кому-нибудь. И все. Допустим число создано внутри метода. Оно хранится в стеке. Вызываем метод MyFunc(object o) или Console.Write(object o). Мы можем передать наше число, которое счас в стеке. Но компилятор упакует его в object - т.е. создаст в куче объект (с возможностями типа object), инициализирует его числом и передаст в метод. В стеке наше число останется. В куче новый объект появится. То же самое будет в случае, когда приводим число к объекту явно... Закончили работу - стек с числом очистился, оникому уже не нужный объект в куче остался. Лучше про боксинг пока не упоминать... Это НЕ ОТНОСИТСЯ к методам работы стека и кучи. Это работа компилятора для согласования типов данных. Код пришли и мне, плиз. ivashkanet дай плиз ссылку на место, где упоминается про "небольшиуе массивы хранятся в стеке " просто я слышал, что создавать стековые массивы нужно специально. (тоже в той книжке. что упоминал, там, где указатели описываются) Может в 3.0 появилось? |
| Автор: ivashkanet 12.7.2007, 10:46 |
Нет, про массивы я все же не видел. Только про List<T>. Но он же сделан на основе масссива... Добавлено через 6 минут и 5 секунд А я о таком даже не слышал. Можно мне ссылку |
| Автор: mr.DUDA 12.7.2007, 12:08 | ||||||
Ага, наконец-то я услышал что хотел: элементы массива хранятся в куче! Вот это и сбивает с толку. Как это value-type может в куче быть. Наверно, надо Рихтера всё-таки почитать З.Ы. Пример с пулом структур: Предположим, есть у нас некая структура данных с размером этак 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-поле. Вот примеры кода:
З.Ы.Ы. за нарушение принципов ООП не ругать! Я о них знаю Добавлено через 41 секунду ivashkanet,
См. оператор stackalloc, но он возвращает указатель а не массив, и требует unsafe. |
| Автор: tol05 12.7.2007, 12:24 |
| может и офф-топик. но все же... А что тогда вообще в куче может быть, по-твоему? Класс, у которого два поля и оба int. Он в куче. А его два поля где? тоже в куче. В куче выделено два блока памяти для хранения двух int Так же и массив. int[10] - в куче выделен блок памяти для хранения десяти int Спасибо за код. Я посмотрю, но комментировать не буду. Просто интересный вариант, со своим правом на существование ... ivashkanet, ссылка - "С# 2005 для профессионалов", |
| Автор: Azzdorf 12.7.2007, 17:33 |
| ок простой вопрос когда мы жмем три чудесные кнопочки и запускаем в Винде (да будет проклят Билл) в диспечере задач --> закладку Процессы там есть колонки: Память и Вирувальная память Вопрсы: Какая-то из них показывает размер Кучи или Стека или это что-то не то?????? И ефективно ли запускать GC после нагруженых методов и функций??? |
| Автор: tol05 12.7.2007, 17:48 |
| Данные для 32-битной Windows размер стека: по умолчанию под стек каждого потока выделяется 1МБайт памяти. (это для "юзания" программой, не учитывает объемы системмных областей) размер кучи: по умолчанию для каждого процесса выделяется 4Гбайт виртуальной памяти. Профайлерами, если не ошибаюсь. То, что ты видишь в диспечере задач - это используемый сейчас объем памяти Да, эффективно. Именно поэтому в public интерфейс и выведены члены класса GC, чтобы с ними работать |
| Автор: Azzdorf 12.7.2007, 18:05 | ||
физической или оперативной??? Добавлено через 2 минуты если оперативной то тогда почему моя маленькая простая прога ест 48метров, когда тотже запищеный файл ворда - 10метров??? |
| Автор: tol05 12.7.2007, 18:31 |
| Azzdorf, воспользуйся поиском, Рихтера почитай (он не только по .Net пишет, в основном - по работе Windows) http://wm-help.net/books-online/book/59464/59464-9.html Память... есть внутренняя память процессора, ОЗУ, файлы подкачки. Процессоры разные, платформы... я не могу точно ответить тебе на вопрос. Про .Net - это да, постараюсь, но это ИМХО больше вопросы к сис.админам.... |
| Автор: Naum 12.7.2007, 18:46 | ||
Память - это собсна оперативная память. Ее размер зависит от того, сколько и каких плат ты воткнул в материнскую плату. Виртуальная память - это, в принципе, тоже оперативная память. Но правильнее "оперативная", потому как все ее содержимое хранится на жестком диске. (Слышал про файл подкачки?)
Это уже не недостаток GC, это уже недостаток всего дотнета. |
| Автор: mr.DUDA 12.7.2007, 20:00 | ||
Потому что дотнет жадный до памяти. Во-первых, JIT-скомпилированный код много занимает, а во-вторых, память изначально выделяется со здоровым запасом. |
| Автор: Azzdorf 13.7.2007, 14:08 | ||
Я вполне знаю что такое оперативка и файл подкачки - просто было интересно что имеено там отображаеться. Всем спасибо, узнал многое, будем читать литературу... Топик закрываю.. |