Каковы некоторые лучшие практики для сокращения использования памяти в C?

Примечание: Преобразование в строковое преобразование

Это происходит просто, если вы пытаетесь рассматривать массив как строку:

$arr = array('foo', 'bar');

echo $arr;  // Notice: Array to string conversion
$str = 'Something, ' . $arr;  // Notice: Array to string conversion

Массив не может быть просто echo 'd или конкатенируется с строкой, потому что результат не определен. PHP будет использовать строку «Array» вместо массива и вызвать уведомление, чтобы указать, что это, вероятно, не то, что было предназначено, и что вы должны проверять свой код здесь. Вероятно, вы захотите что-то вроде этого:

echo $arr[0];  // displays foo
$str = 'Something ' . join(', ', $arr); //displays Something, foo, bar

Или зациклируйте массив:

foreach($arr as $key => $value) {
    echo "array $key = $value";
    // displays first: array 0 = foo
    // displays next:  array 1 = bar
}

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

38
задан Sebastian Mach 8 April 2014 в 11:26
поделиться

15 ответов

В C, на намного более простом уровне, рассматривают следующее;

  • Использование #pragma пакет (1) к байту выравнивает Ваши структуры
  • объединения Использования, где структура может содержать различные типы данных
  • , битовые поля Использования, а не ints для хранения флагов и маленьких целых чисел
  • Избегают использования символьных массивов фиксированной длины, чтобы сохранить строки, реализовать строковый пул и указатели использования.
  • , Где хранение ссылок на перечислимый список строк, например, имени шрифта, хранит индекс в список, а не строку
  • При использовании динамического выделения памяти, вычисляют число элементов, требуемое заранее избегать перевыделений.
27
ответ дан SmacL 27 November 2019 в 03:08
поделиться

Отличный способ ограничения требований к памяти состоит в том, чтобы положиться как можно больше на libc или другие стандартные библиотеки, которые могут быть связаны динамично. Каждый дополнительный DLL или общий объект, который необходимо включать в проект, являются значительным блоком памяти, которую можно быть в состоянии постараться не записывать.

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

0
ответ дан Max 27 November 2019 в 03:08
поделиться

Один прием, который полезен в приложениях, должен создать резервный фонд на черный день памяти. Выделите единственный блок на запуске, который является достаточно большим, который это удовлетворит для задач очистки. Если malloc/new приводят к сбою, выпускают резервный фонд на черный день и добавляют сообщение, позволяющее пользователю знать, что ресурсы трудны, и они должны сохранить и довольно скоро. Это было техникой, используемой во многих приложениях Mac приблизительно 1990.

0
ответ дан plinth 27 November 2019 в 03:08
поделиться

У меня есть представление от Конференции по Встроенным системам, доступной по этой теме. Это с 2001, но тем не менее это очень применимо. См. бумага .

кроме того, если можно выбрать архитектуру целевого устройства, идущего с чем-то как современный ARM с Ползунком V2, или PowerPC с VLE или MIPS с MIPS16, или выбирающего известный - компактные цели как Infineon TriCore или семья SH являются очень хорошим вариантом. Не говоря уже о семье NEC V850E, которая приятно компактна. Или переместитесь в AVR, который имеет превосходную компактность кода (но 8-разрядная машина). Что-либо кроме фиксированной длины 32-разрядный RISC является хорошим выбором!

1
ответ дан jakobengblom2 27 November 2019 в 03:08
поделиться

1), Прежде чем Вы запускаете проект, создаете способом из измерения, сколько памяти Вы используете, предпочтительно на основе на компонент. Тем путем каждый раз, когда Вы вносите изменение, Вы видите его эффекты на использование памяти. Вы не можете оптимизировать то, что Вы не можете измерить.

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

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

Ах да: найдите и зафиксируйте утечки памяти. Любая память, которую можно возвратить, не жертвуя производительностью, является большим запуском.

я потратил партия из времени в прошлом волнении по поводу размера кода. Основные соображения (кроме: удостоверьтесь, что Вы измеряете его во время изготовления так, чтобы Вы видели, что он изменяется):

1) Узнают, на какой код ссылаются, и какой. Если Вы обнаруживаете, что вся библиотека XML связывается в Ваше приложение только для парсинга файла конфигурации с двумя элементами, рассмотрите изменение формата файла конфигурации и/или запись собственного тривиального синтаксического анализатора. Если Вы можете, использовать или источник или двоичный анализ, чтобы нарисовать большой граф зависимостей и искать большие компоненты только с небольшим количеством пользователей: может быть возможно отрезать их только с незначительными перезаписями кода. Будьте готовы играть дипломата: если два различных компонента в Вашем приложении используют XML, и Вы хотите сократить его, то это - два человека, необходимо убедить в преимуществах прокрутки руки что-то, что это в настоящее время - доверяемая, стандартная библиотека.

2) Бездельничают с параметрами компилятора. Консультируйтесь со своей определенной для платформы документацией. Например, можно хотеть уменьшить приемлемое увеличение размера кода по умолчанию из-за встраивания, и на GCC, по крайней мере, можно сказать компилятору только применять оптимизации, которые обычно не увеличивают размер кода.

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

4), Поскольку кто-то еще упомянул, режим ползунка может помочь на ARM. Если Вы только будете использовать его для кода, который не является очень важной производительностью, и оставьте критические стандартные программы в ARM, то Вы не заметите различия.

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

5
ответ дан Steve Jessop 27 November 2019 в 03:08
поделиться

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

7
ответ дан Judge Maygarden 27 November 2019 в 03:08
поделиться

Избегайте фрагментации памяти при помощи своего собственного средства выделения памяти (или тщательно использование средства выделения системы).

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

8
ответ дан nimrodm 27 November 2019 в 03:08
поделиться

Скорее всего, Вы должны будете, выбрал Ваши алгоритмы тщательно. Стремитесь к алгоритмам, которые имеют O (1), или O (зарегистрируйте n), использование памяти (т.е. низко). Например, непрерывные массивы изменяемого размера (например, std::vector) в большинстве случаев требуют меньшей памяти, чем связанные списки.

Иногда, с помощью таблиц поиска может быть больше benefitial и к размеру кода и к скорость. Если Вам только нужны 64 записи в LUT, это составляет 16*4 байта для sin/cos/tan (используйте симметрию!) по сравнению с большой функцией sin/cos/tan.

Сжатие иногда помогает. Простые алгоритмы как RLE легко сжать/распаковать, когда считано последовательно.

, Если Вы имеете дело с графикой или аудио, рассмотрите различные форматы. Paletted или побитно упакованный* графика может быть хорошим компромиссом по качеству, и палитры могут быть совместно использованы через многие изображения, далее уменьшающий размер данных. Аудио может быть уменьшено от 16-разрядного до 8-разрядного или даже 4-разрядное, и стерео может быть преобразован в моно. Частоты дискретизации могут быть уменьшены с 44.1 кГц до 22 кГц или 11 кГц. Эти аудио преобразования значительно уменьшают свой размер данных (и, к сожалению, качество) и тривиальны (кроме передискретизации, но это - то, что аудио программное обеспечение для =]).

*  я предполагаю, что Вы могли подвергнуть это сжатию. Bitpacking для графики обычно обращается к сокращению количества битов на канал, таким образом, каждый пиксель может поместиться в два байта (RGB565 или ARGB155, например) или один (ARGB232 или RGB332) от исходных трех или четыре (RGB888 или ARGB8888, соответственно).

8
ответ дан strager 27 November 2019 в 03:08
поделиться

Все хорошие рекомендации. Вот некоторые подходы дизайна, которые я нашел полезными.

  • Байт, Кодирующий

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

  • Генерация кода

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

  • Быть ненавистником данных

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

9
ответ дан Mike Dunlavey 27 November 2019 в 03:08
поделиться

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

16
ответ дан Dan 27 November 2019 в 03:08
поделиться

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

  • Гарантируют любые таблицы поиска, или другие постоянные данные на самом деле объявляются с помощью const. Если const используется тогда, данные могут храниться в только для чтения (например, флэш-память или EEPROM) память, иначе данные должны быть скопированы в RAM при запуске, и это поднимает и флэш-память и пространство RAM. Установите опции компоновщика так, чтобы это генерировало файл карты, и изучите этот файл для наблюдения точно, где данные выделяются в карте распределения памяти.

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

  • Для сокращения размера кода проверьте настройки оптимизации компилятора. Большинство компиляторов имеет переключатели для оптимизации для скорости или размера кода. Это может стоить экспериментировать с этими опциями видеть, может ли размер скомпилированного кода быть уменьшен. И очевидно, устраните дублирующий код по мере возможности.

  • Проверка, сколько стековой памяти Ваши системные потребности и корректирует выделение памяти компоновщика соответственно (см. ответы на этот вопрос ). Для сокращения использования стека постарайтесь не помещать, большие структуры данных на стеке (для любого значения "больших" относится к Вам).

20
ответ дан Community 27 November 2019 в 03:08
поделиться

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

Некоторые примеры этого:

  1. Синтаксический анализ пар NMEA с конечным автоматом, собирая только обязательные поля в намного более эффективную структуру.
  2. Синтаксический анализ XML использование SAX вместо DOM.
6
ответ дан strager 27 November 2019 в 03:08
поделиться

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

Если память стека ограничена или вы хотите уменьшить размер стека, чтобы освободить место для дополнительной кучи или глобальной ОЗУ, затем рассмотрите следующее:

  1. Сгладьте дерево вызовов , чтобы уменьшить количество переменных в стеке в любой момент времени.
  2. Преобразуйте большие локальные переменные в globals (уменьшает объем используемого стека, но увеличивает объем используемой глобальной RAM). Переменные могут быть объявлены:

    • Глобальная область: видна для всей программы
    • Статическая в области видимости файла: видна в том же файле
    • Статическая в области видимости функции: видна внутри функции
    • ПРИМЕЧАНИЕ: В любом случае, если эти изменения внесены,
1
ответ дан 27 November 2019 в 03:08
поделиться
  • Уменьшите длину и исключите как можно больше строковых констант, чтобы уменьшить пространство кода

  • Тщательно рассмотрите компромиссы между алгоритмами и таблицами поиска, где это необходимо. выделены переменные.

    • Константы, вероятно, находятся в кодовом пространстве.
    • Статические переменные, вероятно, находятся в фиксированных ячейках памяти. По возможности избегайте этого.
    • Параметры, вероятно, хранятся в стеке или в регистрах.
    • Локальные переменные также могут быть выделены из стека. Не объявляйте большие локальные массивы или строки, если код может исчерпать пространство стека в худшем случае.
    • У вас может не быть кучи - может не быть ОС, которая управляет кучей за вас. Это приемлемо? Вам нужна функция malloc ()?
2
ответ дан 27 November 2019 в 03:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: