C # Сборка мусора -> C ++ удалить - PullRequest
5 голосов
/ 07 марта 2012

Я конвертирую проект C # в C ++ и у меня есть вопрос об удалении объектов после использования. В C # GC, конечно, заботится об удалении объектов, но в C ++ это нужно делать явно, используя ключевое слово delete.

Мой вопрос: можно ли просто отслеживать использование каждого объекта в методе, а затем удалять его, как только он выходит из области видимости (т. Е. Завершение / повторное назначение метода)?

Я знаю, что GC ждет определенного размера мусора (~ 1 МБ) перед удалением; делает это потому, что при использовании delete возникают накладные расходы?

Поскольку это игра, которую я создаю, потенциально может быть много объектов, которые создаются и удаляются каждую секунду, поэтому было бы лучше отслеживать указатели, которые выходят из области видимости, и как только этот размер достигнет 1 МБ, чтобы затем удалить указатели?

(в качестве примечания: позже, когда игра оптимизирована, объекты будут загружаться один раз при запуске, поэтому в процессе игры не так много будет удаляться)

Ответы [ 7 ]

9 голосов
/ 07 марта 2012

Ваша проблема в том, что вы используете указатели в C ++.

Это фундаментальная проблема, которую вы должны решить, тогда все ваши проблемы исчезнут. По случайности, я настолько устал от этой общей тенденции, что создал набор слайдов презентации по этому вопросу. - ( CC BY , поэтому не стесняйтесь их использовать).

Посмотрите на слайды. Хотя они, конечно, не совсем серьезны, фундаментальное сообщение все еще верно: Не используйте указатели. Но, если быть более точным, сообщение должно гласить: Не использовать delete.

В вашей конкретной ситуации вы можете оказаться с множеством долгоживущих мелких предметов. Это действительно ситуация, с которой современный GC справляется достаточно хорошо, а умные указатели подсчета ссылок (shared_ptr) обрабатывают менее эффективно. Если (и только если!) Это станет проблемой производительности, рассмотрите возможность переключения на библиотеку небольших объектов .

5 голосов
/ 07 марта 2012

Вы должны использовать RAII как можно больше в C ++, чтобы вам не приходилось явно delete что-либо делать в любое время.
После того, как вы используете RAII с помощью интеллектуальных указателей иваши собственные ресурсы, управляющие классами, каждое динамическое распределение, которое вы делаете, будет существовать только до тех пор, пока на него не возникнут возможные ссылки. Вам не нужно явно управлять какими-либо ресурсами.

3 голосов
/ 07 марта 2012

Ну, самое простое решение может быть просто использовать сборку мусора в C ++. Коллектор Boehm работает хорошо, например. Тем не менее, есть плюсы и минусы (но портирование кода, изначально написанного на C #, было бы вероятный кандидат на случай, когда плюсы во многом перевешивают минусы.)

В противном случае, если вы преобразуете код в идиоматический C ++, не должно быть что много динамически размещаемых объектов, чтобы беспокоиться о. В отличие от C #, C ++ по умолчанию имеет семантику значений и большинство ваших недолговечных объектов должны быть просто локальными переменными, возможно, скопированы, если они будут возвращены, но не распределяется динамически. В C ++ динамическое распределение обычно используется только для объектов сущностей, время жизни которых зависит от внешних событий; например Monster создается в случайное время с вероятностью в зависимости от состояния игры, и удаляется через некоторое время, в реакция на события, которые меняют игровое состояние. В этом случае вы удалить объект, когда монстр перестает быть частью игры. В C #, у вас, вероятно, есть функция dispose, или что-то подобное, для такие объекты, так как они обычно имеют конкретные действия, которые должны быть осуществляется, когда они перестают существовать - такие вещи, как Наблюдатель, если это один из шаблонов, которые вы используете. В C ++ это такого рода вещи обычно обрабатываются деструктором, а вместо позвонив dispose, вы позвоните удалить объект.

3 голосов
/ 07 марта 2012

Управление памятью в C # и C ++ совершенно другое.Вы не должны пытаться имитировать поведение GC .NET в C ++.В .NET выделение памяти происходит очень быстро (в основном перемещение указателя), тогда как освобождение - тяжелая задачаВ C ++ выделение памяти не так уж легко по нескольким причинам, главным образом потому, что нужно найти достаточно большой кусок памяти.Когда куски памяти разных размеров выделяются и освобождаются много раз во время выполнения программы, куча может стать фрагментированной, содержащей много маленьких «дырок» свободной памяти.В .NET этого не произойдет, потому что GC сократит кучу.Однако освобождение памяти в C ++ происходит довольно быстро.

Лучшие практики в .NET не обязательно работают в C ++.Например, пул и повторное использование объектов в .NET в большинстве случаев не рекомендуется, потому что GC продвигает объекты к более высоким поколениям.GC лучше всего подходит для недолговечных объектов.С другой стороны, пул объектов в C ++ может быть очень полезным, чтобы избежать фрагментации кучи.Кроме того, выделение большего фрагмента памяти и использование размещения нового может отлично работать для многих небольших объектов, которые необходимо часто выделять и освобождать, как это может происходить в играх.Ознакомьтесь с общими методами управления памятью в C ++, такими как RAII или размещение новых .

Также я бы порекомендовал приобрести книги «Эффективный C ++» и «Более эффективный C ++».

1 голос
/ 07 марта 2012

Подстановка shared_ptr в каждом экземпляре, в котором вы используете ссылку в C #, даст вам самое близкое приближение при, вероятно, минимальном входном усилии при преобразовании кода.

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

0 голосов
/ 07 марта 2012

GC особенность c ++ много обсуждалась в SO.

Попробуйте прочитать это !!

Сборка мусора в C ++

0 голосов
/ 07 марта 2012

При освобождении объектов нужно учитывать гораздо больше вещей, чем просто вызывать delete всякий раз, когда он выходит из области видимости. Вы должны убедиться, что вы вызываете delete только один раз и вызываете его только один раз все указатели на этот объект вышли из области видимости. Сборщик мусора в .NET обрабатывает все это для вас.

Конструкция, которая в основном соответствует конструкции в C ++, это tr1::shared_ptr<>, которая сохраняет счетчик ссылок на объект и освобождает его, когда он падает до нуля. Первый подход к запуску состоит в том, чтобы сделать все ссылки C # на C ++ tr1::shared_ptr<>. Затем вы можете перейти в те места, где это узкое место в производительности (только после того, как вы проверили с помощью профиля, что это фактическое узкое место), и перейти на более эффективную обработку памяти.

...