Распределение памяти / освобождение Узкое место?

Насколько узким местом является распределение / освобождение памяти в типичных программах реального мира? Ответы любого типа программ, в которых производительность обычно имеет значение, приветствуются. Являются ли приличные реализации коллекции malloc / free / garbage достаточно быстрыми, что это всего лишь узкое место в нескольких угловых случаях, или же самое важное преимущество для критически важных программных продуктов может быть достигнуто за счет того, чтобы уменьшить объем распределения памяти или иметь более быстрый malloc / free / assembly мусора?

Примечание. Я не говорю о реальном времени здесь. К критическим по производительности, я имею в виду вещи, где важна пропускная способность, но латентность не обязательно.

Изменить: Хотя я упоминаю malloc, этот вопрос не предназначен для C / C ++.

Это важно, особенно по мере того, как fragmentация растет, и распределителю приходится больше искать более крупные кучи для смежных регионов, которые вы запрашиваете. Большинство приложений, чувствительных к характеристикам, обычно записывают свои собственные блокирующие блок-блокировки (например, они запрашивают ОС для памяти 16 МБ за один раз, а затем выгружают ее в фиксированные блоки 4 кб, 16 кб и т. Д.), Чтобы избежать этой проблемы.

В играх, которые я видел, звонки в malloc () / free () потребляют до 15% CPU (в плохо написанных продуктах) или с тщательно написанными и оптимизированными блочными распределителями всего 5%. Учитывая, что игра должна иметь согласованную пропускную способность в шестьдесят герц, если она останавливается на 500 мс, а сборщик мусора иногда бывает непрактичен.

Почти каждое высокопроизводительное приложение теперь должно использовать streamи для использования параллельных вычислений. В этом случае при создании приложений на C / C ++ возникает реальный убийца скорости выделения памяти.

В приложении C или C ++ malloc / new должен блокировать глобальную кучу для каждой операции. Даже без конкуренции блокировки далеки от свободы и их следует избегать как можно больше.

Java и C # лучше, потому что streamи были разработаны с самого начала, а распределители памяти работают из пулов для streamов. Это можно сделать и на C / C ++, но это не автоматическое.

Во-первых, поскольку вы сказали malloc, я предполагаю, что вы говорите о C или C ++.

Распределение и освобождение памяти, как правило, являются значительным узким местом для реальных программ. Когда вы выделяете или освобождаете память, многое происходит «под капотом», и все это зависит от системы; память может быть действительно перемещена или деfragmentирована, страницы могут быть реорганизованы – нет никакого независимого от платформы способа узнать, какое влияние это будет. Некоторые системы (например, множество игровых консолей) также не выполняют деfragmentацию памяти, поэтому в этих системах вы начнете получать ошибки из памяти, поскольку память становится fragmentированной.

Типичным обходным решением является выделение как можно большего количества памяти спереди и зависание, пока ваша программа не выйдет. Вы можете использовать эту память для хранения больших monoлитных наборов данных или использовать реализацию пула памяти, чтобы использовать ее в кусках. Многие стандартные реализаторы библиотек C / C ++ делают определенную сумму памяти, объединив себя именно по этой причине.

Однако нет двух способов: если у вас есть программа C / C ++, зависящая от времени, выполнение большого объема выделения / освобождения памяти приведет к урон производительности.

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

Теперь, захват очень больших блоков памяти может быть проблемой. И захватить, но не избавиться от памяти – это то, о чем я буду беспокоиться.

На Java и JVM-языках новые объекты теперь очень, очень и очень быстро.

Вот одна достойная статья того парня, который знает свои вещи с некоторыми ссылками внизу на более связанные ссылки: http://www.ibm.com/developerworks/java/library/j-jtp09275.html

В Java (и, возможно, на других языках с достойной реализацией GC) выделение объекта очень дешево. В SUN JVM требуется всего 10 циклов ЦП. Malloc в C / c ++ намного дороже, просто потому, что он должен делать больше работы.

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

Java VM будет требовать и освобождать оперативную память от операционной системы в значительной степени от того, что делает код приложения. Это позволяет ему захватывать и выпускать память в больших кусках, что намного эффективнее, чем в небольших индивидуальных операциях, так как вы получаете ручное управление памятью.

Эта статья была написана в 2005 году, и управление памятью в стиле JVM уже было впереди улиц. С тех пор ситуация улучшилась.

На каком языке может похвастаться более высокая производительность выделения, язык Java или C / C ++? Ответ может вас удивить: распределение в современных JVM намного быстрее, чем в лучших реализациях malloc. Общий путь кода для нового объекта Object () в HotSpot 1.4.2 и более поздних версиях составляет приблизительно 10 машинных инструкций (данные, предоставленные Sun, см. Раздел «Ресурсы»), тогда как наиболее эффективные реализации malloc в C требуют в среднем от 60 до 100 инструкций для каждого вызова ( Detlefs, et al., См. Ресурсы). И производительность распределения не является тривиальным компонентом общей производительности – тесты показывают, что многие программы C и C ++ реального мира, такие как Perl и Ghostscript, тратят от 20 до 30 процентов своего общего времени выполнения в malloc и бесплатно – намного больше, чем накладные расходы на распределение и garbage collection для здорового Java-приложения.

Выделение и освобождение памяти с точки зрения производительности – относительно дорогостоящие операции. Вызовы в современных операционных системах должны полностью переходить к ядру, чтобы операционная система могла иметь дело с виртуальной памятью, подкачкой / сопоставлением, защитой исполнения и т. Д.

С другой стороны, почти все современные языки программирования скрывают эти операции за «распределителями», которые работают с заранее выделенными буферами.

Эта концепция также используется большинством приложений, которые сосредоточены на пропускной способности.

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

Чтобы говорить с вами напрямую, если я правильно понимаю, критерий эффективности использования производительности – это пропускная способность.

Это для меня означает, что вы должны смотреть почти исключительно на NUMA- осведомленных распределителей .

Ни одна из ранних ссылок; Документ IBM JVM, Microquill C, SUN JVM. Поощряйте этот момент, поэтому я очень подозреваю их применение сегодня, где, по крайней мере, на AMD ABI, NUMA является выдающимся controllerом памяти-процессора.

Руки вниз; реальный мир, фальшивый мир, какой бы мир … NUMA не знает, какие запросы / технологии использования памяти быстрее. К сожалению, сейчас я запускаю Windows, и я не нашел «numastat», который доступен в Linux.

Мой друг подробно рассказал об этом в своем применении к ядру FreeBSD.

Несмотря на то, что я могу показать на ходу, типично ОЧЕНЬ большое количество запросов памяти локальных узлов на вершине удаленного узла (подчеркивая очевидное преимущество пропускной способности производительности ), вы можете испытать уверенность в себе, и это, вероятно, будет тем, что вам нужно так как ваша производительность charicterisitc будет очень специфичной.

Я знаю, что во многих отношениях, по крайней мере, более ранние версии 5.x VMWARE выглядели довольно слабо, в то время, по крайней мере, для того, чтобы не использовать NUMA, часто требуя страниц с удаленного узла. Тем не менее, VM – это очень уникальный зверь, когда дело доходит до отсечения памяти или контейнеризации.

Одна из ссылок, которые я привел, касается внедрения API Microsoft для AMD ABI, у которой есть специализированные интерфейсы выделения NUMA для использования разработчиками наземных приложений пользователей;)

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

Они в какой-то мере покрывают в количественном отношении, по крайней мере, для их использования, то, что точный компромисс между пространством / временем, как правило, они идентифицировали LFH (oh ya и, кстати, LFH – это просто режим, очевидно, стандартной кучи) или аналогично разработанный подход по существу потребляет значительно больше памяти с летучей мыши, но со временем может закончиться использованием меньше памяти … grafix также опрятно …

Я бы подумал, однако, что выбор внедрения HEAP на основе вашей типичной рабочей нагрузки после того, как вы ее хорошо понимаете;) является хорошей идеей, но для того, чтобы хорошо понимать ваши потребности, сначала убедитесь, что ваши основные операции правильные, прежде чем вы оптимизируете эти факторы и цели;)

Это то, где система распределения памяти c / c ++ работает наилучшим образом. Страtagsя распределения по умолчанию в большинстве случаев подходит для большинства случаев, но ее можно изменить в соответствии с тем, что необходимо. В системах GC вы не можете многое изменить для страtagsй распределения. Конечно, есть цена для оплаты, и это необходимо для отслеживания распределения и бесплатного их использования. C ++ делает это дополнительно, и страtagsя распределения может быть указана для каждого classа с использованием нового оператора:

class AClass { public: void *operator new (size_t size); // this will be called whenever there's a new AClass void *operator new [] (size_t size); // this will be called whenever there's a new AClass [] void operator delete (void *memory); // if you define new, you really need to define delete as well void operator delete [] (void *memory);define delete as well }; 

Многие шаблоны STL позволяют также определять пользовательские распределители.

Как и все, что связано с оптимизацией, вы должны сначала определить через анализ времени выполнения, если распределение памяти действительно является узким местом, прежде чем писать собственные распределители.

Согласно технической спецификации MicroQuill SmartHeap , «типичное приложение […] тратит 40% своего общего времени на управление памятью». Вы можете принять эту цифру как верхнюю границу, я лично считаю, что типичное приложение тратит больше 10-15% времени выполнения, выделяя / освобождая память. Это редко является узким местом в однопоточном применении.

В многопоточных приложениях C / C ++ стандартные распределители становятся проблемой из-за конфликта блокировок. Здесь вы начинаете искать более масштабируемые решения. Но имейте в виду закон Амдаля .

Другие рассмотрели C / C ++, поэтому я просто добавлю небольшую информацию о .NET.

В распределении кучи .NET, как правило, очень быстро, так как это просто вопрос захвата памяти в нулевой части генерации кучи. Очевидно, что это не может продолжаться вечно, в которое входит garbage collection. Сбор мусора может существенно повлиять на производительность вашего приложения, поскольку streamи пользователей должны быть приостановлены во время уплотнения памяти. Чем меньше полных собраний, тем лучше.

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

Независимо от того, действительно ли это важно в вашем приложении или нет, зависит от нескольких факторов, и вы должны профилировать приложение с фактическими данными, прежде чем обращаться к такой оптимизации.

Практически все вы не в базе, если вы говорите о куче Microsoft. Синхронизация без труда обрабатывается, как и fragmentация.

Текущая perferrred heap – это LFH ( LOW FRAGMENTATION HEAP), она по умолчанию установлена ​​в Vista + OS и может быть настроена на XP через gflag, без особых проблем

Легко избежать любых проблем с блокировкой / блокировкой / конфликтом / шинами, а также с

 HEAP_NO_SERIALIZE 

во время HeapAlloc или HeapCreate. Это позволит вам создать / использовать кучу, не вступая в блокированное ожидание.

Я рекомендовал бы создать несколько куч с помощью HeapCreate и определить макрос, возможно, mallocx (enum my_heaps_set, size_t);

было бы неплохо, конечно, вам нужно realloc, бесплатно и настроить как подходящее. Если вы хотите получить фантазию, сделайте бесплатный / realloc автоматически определите, какой дескриптор кучи на нем собственный, оценив адрес указателя или даже добавив некоторую логику, чтобы позволить malloc определить, какую кучу использовать на основе ее идентификатора streamа, и построить иерархию кучи для streamов и общие глобальные кучи / пулы.

Heap * api называются внутренне malloc / new.

Вот хорошая статья о некоторых проблемах управления динамической памятью , с некоторыми даже более хорошими ссылками . Инструмент и анализ активности кучи.

  • Как обрабатывать OutOfMemoryError в Java?
  • Почему происходит сбой этой программы: передача std :: string между DLL
  • Какова стоимость использования автореферата в cocoa?
  • Как работают malloc () и free ()?
  • Почему у меня возникают разные результаты, когда я разыгрываю указатель после его освобождения?
  • Является ли хорошей практикой освобождение NULL-указателя в C?
  • Разделение памяти Android
  • Как я могу получить размер блока памяти, выделенного с помощью malloc ()?
  • Как выделена память для статической переменной?
  • R управления памятью / не может выделить вектор размера n Mb
  • Каков максимальный размер кучи по умолчанию для JVM Sun от Java SE 6?
  • Interesting Posts

    Xcode 8 Beta 3 Используйте устаревшую версию Swift

    iPhone – UILabel, содержащий текст с несколькими шрифтами одновременно

    Отправка и получение 2D-массива по MPI

    Редактирование заявления о суммировании автоматической суммы

    Как определить, что вызывает повторный автозапуск установщика Windows?

    Эмулирование правой клавиши Ctrl на клавиатуре MacBook Pro без фактической правой клавиши Ctrl

    Как получить текущий момент в формате ISO 8601 с датой, часом и минутой?

    Как получить данные POST с urlencoded с помощью $ http без jQuery?

    Просмотр Android EditText Плавающая подсказка в дизайне материалов

    Отсутствие вывода консоли при использовании AllocConsole и целевой архитектуры x86

    Использование профилей памяти Perl и обнаружение утечки?

    Каково значение # в URL-адресе и как я могу это использовать?

    Как получить список пользователей, которые вошли в систему на удаленном компьютере?

    Получите определенное местоположение GPS как-то на окнах 8

    Выделяет subString в TableCell (s), который используется для JTable filetering

    Давайте будем гением компьютера.