Управление памятью в программировании становится неактуальной проблемой?


38

История вопроса
Я повторно посетил старый (но отличный) сайт, на котором я не был целую вечность - Alioth Language Shootout ( http://benchmarksgame.alioth.debian.org/ ).

Я начал программировать на C / C ++ несколько лет назад, но с тех пор работал почти исключительно на Java из-за языковых ограничений в проектах, в которых я принимал участие. Не вспоминая рисунки, я хотел примерно увидеть, насколько хорошо Java выступил против C / C ++ с точки зрения использования ресурсов.

Время выполнения все еще было относительно хорошим: Java в худшем случае выполняла в 4 раза медленнее, чем C / C ++, но в среднем примерно (или ниже) в 2 раза. Из-за особенностей реализации самой Java, это не было неожиданностью, и время ее выполнения было фактически ниже, чем я ожидал.

Настоящим кирпичиком было выделение памяти - в худшем случае Java выделяла:

  • колоссальные 52 раза больше памяти, чем C
  • и в 25 раз больше, чем C ++.

Память в 52 раза ... Абсолютно противная, правда? ... либо это? Память сейчас сравнительно дешевая.

Вопрос:
Если мы не говорим с точки зрения целевых платформ со строгими ограничениями на рабочую память (т.е. встроенные системы и т. П.), Должно ли использование памяти быть проблемой при выборе языка общего назначения сегодня?

Я спрашиваю частично, потому что я рассматриваю переход на Scala в качестве основного языка. Мне очень нравятся его функциональные аспекты, но из того, что я вижу, он даже дороже с точки зрения памяти, чем Java. Однако, поскольку память с каждым годом становится все быстрее, дешевле и в изобилии (кажется, что все труднее найти потребительский ноутбук без как минимум 4 ГБ ОЗУ DDR3), нельзя ли утверждать, что управление ресурсами становится все более и более не имеет значения по сравнению с (возможно, дорогостоящими в реализации) функциями языка высокого уровня, которые позволяют быстрее создавать более читаемые решения?


32
Не забывайте, что только потому, что Java выделяет в 52 раза больше памяти, чем C, для небольшого теста, это не означает, что для большого приложения будет использоваться в 52 раза больше памяти. Львиная доля этой памяти будет фиксированной величиной, требуемой JVM, и чем больше становится ваше приложение, тем менее значимой станет эта часть.
Carson63000

4
Если мобильная разработка не имеет значения, тогда да.
JeffO

3
Вопрос в том, насколько плох тест Java по сравнению с C / C ++ и что он означает с точки зрения выбора между двумя языками. Я считаю, что это актуально, актуально для всех программистов, понятно, сфокусировано и способно дать разумный ответ в его нынешнем виде. Я проголосовал за открытие.
ГленПетерсон

Большинство проблем с производительностью вызваны и устранены на уровне проектирования, а не на уровне инструмента. Некоторые проблемы требуют детализации 1 мс и, следовательно, требуют C / C ++. Если у вас есть свобода действий, например, 10 мс, тогда, возможно, Scala или Java - хороший вариант. Большинство контроллеров ввода для игр работают на уровне 50-100 мс. Многие люди сегодня пишут критические разделы на одном языке, а остальные программы на другом.
ГленПетерсон

4
При рассмотрении «25x больше, чем C ++» в этом тесте необходимо учитывать постоянное добавление времени выполнения (около 13 Мб). По мере того, как проблема становится больше, требования к памяти во время выполнения уменьшаются в процентах от всей программы. Если использование памяти C ++ меньше 1 МБ, если вы вычтете использование памяти C ++ из использования памяти Java, вы получите довольно постоянное значение.

Ответы:


34

Управление памятью чрезвычайно важно, поскольку оно определяет, как быстро что-то появляется, даже если у этого что-то много памяти. Лучшим и наиболее каноническим примером являются игры с титулом AAA, такие как Call of Duty или Bioshock. По сути, это приложения реального времени, которые требуют значительного контроля с точки зрения оптимизации и использования. Проблема не в использовании как таковом, а в управлении.

Это сводится к двум словам: сборка мусора. Алгоритмы сборки мусора могут вызывать небольшие сбои в производительности или даже вызывать зависание приложения на секунду или две. В основном безвреден в бухгалтерском приложении, но потенциально разрушителен с точки зрения пользовательского опыта в игре Call of Duty. Таким образом, в приложениях, где время имеет значение, языки с сборкой мусора могут быть чрезвычайно проблематичными. Это одна из целей разработки Squirrel, например, которая пытается исправить проблему, которая возникает у Lua с его GC, используя вместо этого подсчет ссылок.

Это больше головная боль? Конечно, но если вам нужен точный контроль, вы должны с этим мириться.


14
-1 «... буквально смертельно опасно в игре ...» - Моя повседневная работа - это система безопасности, критически важная для безопасности жизни. Худшее, что случается в игровом программном обеспечении, это то, что писатель обанкротился, потому что его дерьмо, и никто его не покупает. Это различие, которое не следует упрощать.
Mattnz

4
@mattnz Плохой выбор слов с моей стороны. Это было исправлено. Я не собирался тривиализировать что-либо.
Мировой инженер

19
@Mattnz: Если вы знакомы с играми, он, очевидно, подразумевает, что это может быть смертельным для вашего персонажа , что является абсолютно верным утверждением.
Мейсон Уилер

8
+1, потому что у ответчика есть бриллиант, поэтому ответ должен быть правильным.
PSR

8
Сборщики мусора в реальном времени существуют целую вечность.
Йорг Миттаг

30

Настоящим кирпичиком было выделение памяти - в худшем случае Java выделяла в 52 раза больше памяти, чем С, и в 25 раз больше, чем С ++.

Вы понимаете цифры, на которых основываете свой вопрос?

  • Сколько памяти было выделено?
  • Что делали программы?

Когда между этими программами на Java и C существует большое несоответствие, это в основном распределение памяти JVM по умолчанию по сравнению с тем, что нужно libc:


  • Java-программа n-body 13,996 КБ :: C-программа 320 КБ :: Free Pascal 8 КБ

Посмотрите на задачи, которые требуют выделения памяти (или используйте дополнительные буферы для накопления результатов от многоядерных программ):

  • Мандельброт
    Java-программа 67 , 880 КБ :: C-программа 30 , 444 КБ


  • Java-программа с k-нуклеотидом 494 , 040 КБ :: C-программа 153 , 452 КБ


  • Java-программа с обратным дополнением 511 , 484 КБ :: C-программа 248 , 632 КБ


  • Java-программа regex-dna 557 , 080 КБ :: C-программа 289 , 088 КБ


  • Java-программа с двоичными деревьями 506 , 592 КБ :: C-программа 99 , 448 КБ

... использование памяти должно быть проблемой при выборе языка общего назначения сегодня?

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


3
Ваша точка зрения о том, чтобы копаться в цифрах, верна, и на этом сайте определенно есть несколько заявлений об отказе от ответственности, касающихся их тестов. Ваш ответ будет усилен путем непосредственного решения основного вопроса: «Должно ли использование памяти быть проблемой?»

1
Отличный ответ, который спас относительно плохой вопрос (смутно заданный тест еще хуже, чем преждевременная оптимизация :). Данные, которые поддерживают анализ, хорошо представлены, конкретны и являются отличной пищей для размышлений. Определенно стоит награды за «примерный ответ» .
комнат

17

Как и во всем, это компромисс.

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


8

Это зависит от ряда факторов, особенно от масштаба, в котором вы работаете.

Просто в качестве аргумента, давайте предположим, что 30-кратное различие в памяти и 2-кратное использование процессора.

Если вы имеете дело с интерактивной программой, которая потребовала бы 10 мегабайт памяти и 1 миллисекунду ЦП, если она написана на C, это в значительной степени несущественно - 300 мегабайт памяти и 2 миллисекунды для выполнения обычно не имеют значения на типичном рабочем столе, и вряд ли будет много значить даже на телефоне или планшете.

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

Другой фактор, который вам действительно нужно учитывать, это то, какую разницу в стоимости разработки вы увидите для своей конкретной задачи. Прямо сейчас вы в основном смотрите на одну сторону уравнения. Чтобы получить хорошее представление о затратах и ​​выгодах, вам (очевидно, достаточно) нужно взглянуть как на издержки, так и на выгоды, а не на отдельную. Реальный вопрос в основном: "х больше, чем у?" - но вы не можете определить это, глядя только на х. Вам явно нужно взглянуть на y.


2
+1 за отметку шкалы. Взгляните на эту статью, чтобы по-настоящему оценить управление ресурсами в больших масштабах.
Гай Кодер

6

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

Вы делаете что-то не так, если это ваш код:

static List<string> Cache;

...
Cache.Add(foo); //and then never remove anything from Cache

Сборщик мусора не может волшебным образом знать, что вы никогда не будете использовать какую-либо ссылку снова, если вы не сделаете ее, чтобы вы не могли использовать ее снова, то есть Cache=null, фактически, вы эффективно предупреждаете сборщика мусора, что «эй, я не смогу получить доступ к нему больше. Делай, что вы будете с ним "

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

Есть также места, где вы не можете разместить сборщик мусора. Например, ATTiny84 - это микроконтроллер с 512 байтами кода ПЗУ и 32 байтами оперативной памяти. Удачи! Это крайность, и, вероятно, она не будет запрограммирована ни на что, кроме сборки, но все же. В других случаях у вас может быть 1М памяти. Конечно, вы можете установить сборщик мусора, но если процессор работает очень медленно (либо из-за ограничений, либо из-за экономии заряда батареи), вам не нужно использовать сборщик мусора, потому что слишком дорогое отслеживание, что может знать программист ,

Также становится значительно сложнее использовать сборку мусора, когда вам требуется гарантированное время отклика. Например, если у вас есть монитор сердечного ритма или что-то еще, и когда он получает 1сигнал через какой-то порт, вы должны гарантировать, что вы можете ответить на него правильным сигналом или чем-то в течение 10 мс. Если в середине вашей процедуры ответа сборщик мусора должен сделать пропуск, и в итоге ему требуется 100 мс, чтобы ответить, это может быть кто-то мертвый. Сборку мусора очень сложно, если не невозможно, использовать, когда необходимо гарантировать соблюдение сроков.

И, конечно, даже на современном оборудовании в некоторых случаях вам нужны дополнительные 2% производительности, не беспокоясь об издержках сборщика мусора.


3

Как сказал Дональд Кнут, преждевременная оптимизация - корень всего зла. Если у вас нет причин полагать, что память станет узким местом, не беспокойтесь об этом. И учитывая, что закон Мура по-прежнему обеспечивает увеличенный объем памяти (даже несмотря на то, что мы не извлекаем из него более быстрый однопоточный код), есть все основания полагать, что в будущем мы будем еще меньше ограничены в памяти, чем мы сегодня.

Тем не менее, если оптимизация не является преждевременной, обязательно сделайте это. Я лично сейчас работаю над проектом, в котором я очень подробно разбираюсь в использовании памяти, мне действительно нужен точный контроль, и уборка мусора убьет меня. Поэтому я делаю этот проект на C ++. Но этот выбор, кажется, является событием раз в несколько лет для меня. (Надеюсь, через несколько недель я больше не буду касаться C ++ еще несколько лет.)


4
Именно так мы получаем раздутые корпоративные программы на невероятно медленных компьютерах, которые продолжают пейджинг. Все говорят: «Конечно, мое приложение требует больше памяти, но кого это волнует, оно практически бесплатно!» и затем вы получаете полный набор приложений, требующих памяти, которые заставляют машину с 4 ГБ ОЗУ работать медленнее, чем машина с 512 МБ ОЗУ 10 лет назад.
MrFox

@MrFox На самом деле проблема с корпоративным программным обеспечением состоит в том, что люди, которые решают использовать его, не люди, которые страдают с этим. См. Lists.canonical.org/pipermail/kragen-tol/2005-April/000772.html для превосходного описания причин его поломки. В остальном, вы упустили мое указание на то, что иногда необходимо беспокоиться об использовании памяти?
Btilly

3

Для людей, имеющих дело с «большими данными», управление памятью остается огромной проблемой. Все программы по астрономии, физике, биоинформатике, машинному обучению и т. Д. Имеют дело с наборами данных объемом в несколько гигабайт, и программы работают намного быстрее, если соответствующие части можно сохранить в памяти. Даже работа на машине с 128 ГБ ОЗУ не решает проблему.

Существует также вопрос использования преимуществ графического процессора, хотя, возможно, вы бы классифицировали его как встроенную систему. Большая часть сложного мышления при использовании CUDA или OpenCL сводится к проблемам управления памятью при переносе данных из основной памяти в память GPU.


1

Честно говоря, во многих Java есть некоторые по-настоящему и бессмысленно взрывоопасные шаблоны, которые просто убивают производительность и наполняют память, но я удивляюсь, сколько из этой памяти - просто JVM, которая в теории (хе) позволяет вам запускать одно и то же приложение в нескольких средах без необходимости полностью переписывать новые. Следовательно, вопрос компромисса в дизайне сводится к следующему: «Сколько памяти пользователей стоит для вас такого преимущества при разработке?»

Это - IMO, совершенно стоящий и разумный компромисс, чтобы рассмотреть. Что меня бесит, так это то, что современные ПК настолько мощные, а память - дешевая, поэтому мы можем полностью игнорировать такие проблемы, взламывать функции и раздувать код, а также лениться в отношении выбора до такой степени, что это кажется большим количеством вещей. Сейчас я работаю на ПК с Windows, занимает столько же времени, сколько и в Windows '95. Если серьезно, Word? Сколько нового дерьма, в котором действительно нуждается 80% их пользовательской базы, они могли бы добавить за 18 лет? Уверен, что у нас была предварительная проверка правописания, верно? Но мы говорили о памяти, которая не обязательно быстрая, если у вас ее много, поэтому я отвлекся.

Но, конечно, если вы можете сделать приложение за 2 недели по цене, может быть, нескольких лишних мегабайт, а не 2 лет, чтобы получить версию «нужно всего лишь несколько К», стоит подумать о том, как сравнить несколько мегабайт ( Я предполагаю) 4-12 концертов на средней машине пользователей, прежде чем насмехаться над идеей быть таким неряшливым.

Но какое это имеет отношение к Scala, кроме вопроса о компромиссе? Тот факт, что это сборка мусора, вовсе не означает, что вы не всегда должны думать о потоке данных с точки зрения того, что находится в области видимости и замыканиях, а также о том, следует ли их оставлять без присмотра или использовать таким образом, чтобы это было освобождается от GC, когда он больше не нужен. Это то, о чем даже нам, веб-разработчикам JavaScript UI, приходилось задумываться, и мы надеемся, что это будет продолжаться по мере того, как мы будем распространяться на другие проблемные области, такие как безрассудный рак (который вы все должны были убить с помощью Flash, Applets или чего-то подобного, когда у вас была такая возможность) что мы есть.


0

Управление памятью в программировании становится неактуальной проблемой?

Управление памятью (или контроль) на самом деле является основной причиной, по которой я использую C и C ++.

Память сейчас сравнительно дешевая.

Не быстрая память. Мы по-прежнему рассматриваем небольшое количество регистров, например, кеш данных объемом 32 КБ для L1 на i7, 256 КБ для L2 и 2 МБ для L3 / ядро. Это говорит:

Если мы не говорим с точки зрения целевых платформ со строгими ограничениями на рабочую память (т.е. встроенные системы и т. П.), Должно ли использование памяти быть проблемой при выборе языка общего назначения сегодня?

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

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

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

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

введите описание изображения здесь

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

За последние пару десятилетий я разработал и внедрил несколько ячеистых систем, и их скорость часто была очень пропорциональна их использованию памяти. Несмотря на то, что я работаю с этим, гораздо больше памяти, чем когда я начинал, мои новые сетчатые системы более чем в 10 раз быстрее, чем мой первый проект (почти 20 лет назад), и в значительной степени потому, что они используют около 1/10 память. В новейшей версии даже используется индексированное сжатие для сжатия как можно большего количества данных, и, несмотря на накладные расходы по обработке при декомпрессии, сжатие фактически улучшило производительность, потому что, опять же, у нас так мало драгоценной быстрой памяти. Теперь я могу уместить сетку из миллиона полигонов с координатами текстуры, сгибом кромок, назначениями материалов и т. Д. Вместе с пространственным индексом для него примерно в 30 мегабайт.

Вот изменчивый прототип с более чем 8 миллионами четырехугольников и многоуровневой схемой подразделения на i3 с GF 8400 (это было несколько лет назад). Это быстрее, чем моя неизменяемая версия, но не используется в производстве, так как я обнаружил, что неизменяемая версия намного проще в обслуживании, и снижение производительности не так уж плохо. Обратите внимание, что в каркасном изображении указаны не фасеты, а заплатки (в действительности, это кривые, иначе вся сетка будет сплошной черной), хотя кисть изменяет все точки фасета.

введите описание изображения здесь

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

Для такого рода вещей действительно полезно работать с языком, который позволяет проектировать высокоуровневые объекты, такие как, например, C ++, и при этом сохранять эти объекты в одном или нескольких смежных массивах с гарантией того, что память все такие объекты будут представлены непрерывно и без каких-либо ненужных накладных расходов памяти на объект (например: не все объекты нуждаются в отражении или виртуальной диспетчеризации). Когда вы на самом деле переходите в эти критические для производительности области, это становится повышением производительности, когда такой контроль над памятью, например, работает с пулами объектов и использует примитивные типы данных, чтобы избежать накладных расходов на объекты, затрат на сборку мусора и обеспечить постоянный доступ к памяти. вместе смежные.

Поэтому управление / контроль памяти (или ее отсутствие) на самом деле является доминирующей причиной в моем случае выбора того, какой язык наиболее продуктивно позволяет мне решать проблемы. Я действительно пишу свою долю кода, которая не критична для производительности, и для этого я склонен использовать Lua, который довольно легко внедрить из C.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.