Відмова від оперативної пам’яті / помилка OOM


11

Це питання досить тривалий, тому я задаю питання вгорі, а потім перейду до свого методу приходу до питань:

  1. Хіба (на основі Busybox) rm не виконується, оскільки не вистачало суміжної оперативної пам’яті?
  2. Якщо так, чи існує легкий метод дефрагментації DMA - не вдаючись до перезавантаження системи?
  3. Якщо ні, то що це спричинило? Як я можу запобігти цьому в майбутньому?

Після того, як наша тестова система працювала досить інтенсивно протягом останніх кількох днів - я telnet'd в систему і перевіряв результати тестів. Коли я прийшов видалити деякі дані, система повернула командний рядок (як би команда виконана правильно). Коли я прийшов перевірити каталог на наявність іншого набору результатів, я побачив, що файл все ще існує (використовуючи ls).

Після цього я помітив, що все більше моїх команд оболонок не виконують так, як очікувалося.

Почну з виводу з dmesg після того, як rm не вдалося виконати правильно:

Не вдалося виділити довжину 61440 від процесу 6821 (rm)

DMA на кожен процесор:

CPU 0: привіт: 0, btch: 1 usd: 0

Active_anon: 0 active_file: 1 Inactive_anon: 0 Inactive_file: 0 unvictable: 6 брудний: 0 знижок: 0 нестабільний: 0 безкоштовно: 821 плита: 353 зіставлено: 0 сторінок: 0 відмов: 0

Безкоштовний DMA: 3284kB хв: 360kB низький: 448kB високий: 540kB active_anon: 0kB Inactive_anon: 0kB active_file: 4kB Inactive_file: 0kB unvicable: 24kB присутній: 8128kB сторінок_scanned: 0 all_unreclaimable? ні

lowmem_reserve []: 0 0 0

DMA: 31 * 4kB 47 * 8kB 42 * 16kB 64 * 32kB 1 * 64kB 0 * 128kB 0 * 256kB 0 * 512kB 0 * 1024kB 0 * 2048kB 0 * 4096kB = 3284kB

14 загальних сторінок кеш-сторінки

Неможливо виділити оперативну пам’ять для даних процесу, помилка 12

Спочатку я вважав, що не зможу запустити програму у найбільшій частині суміжної пам'яті. Це означає, що DMA був надто фрагментарним, і мені доведеться знайти спосіб дефрагментації пам'яті системи.

Тоді я зробив швидку перевірку математики / розумності і зрозумів, що програма повинна була мати можливість працювати в єдиному суміжному слоті пам’яті на 64 КБ. Rm запитував 61440 байт (60 кБ).

Я зробив старий добрий "ручний дефрагмент" і перезавантажив систему. Коли я перезавантажував систему, я виводив / proc / buddyinfo:

Node 0, zone DMA 2 8 3 12 0 1 0 1 0 1 0

Яку підозрюю карту:

  • 2 х 4 кБ
  • 8 х 8 кБ
  • 3 х 16 кБ
  • 12 х 32 кБ
  • 1 х 128 кБ
  • 1 х 512 кБ

Але якщо підсумовувати вищевказаний список значень, він не відповідає результату / proc / meminfo :

MemTotal:           6580 kB
MemFree:            3164 kB
Buffers:               0 kB
Cached:              728 kB
SwapCached:            0 kB
Active:              176 kB
Inactive:            524 kB
Active(anon):          0 kB
Inactive(anon):        0 kB
Active(file):        176 kB
Inactive(file):      524 kB`
Unevictable:           0 kB
Mlocked:               0 kB
MmapCopy:            844 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:             0 kB
Mapped:                0 kB
Slab:               1268 kB
SReclaimable:        196 kB
SUnreclaim:         1072 kB
PageTables:            0 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:        3288 kB
Committed_AS:          0 kB
VmallocTotal:          0 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB

Для резюме мої запитання:

  1. Хіба rm не виконується, оскільки не вистачало суміжної оперативної пам’яті?
  2. Якщо так, чи існує легкий метод дефрагментації DMA - не вдаючись до перезавантаження системи?
  3. Якщо ні, то що це спричинило? Як я можу запобігти цьому в майбутньому?

Я використовую XPort Pro (8MB, Linux OS) Lantronix під управлінням uClinux версії 2.6.30. Оболонка, що використовується, є затишною.


Незначна точка: у списку фрагментів пам'яті ви залишилися 1 х 2048 кБ. Якщо ви включите це, то сума становить 3192 кБ, що дуже близьке до 3164 кБ, переліченому в / proc / meminfo.
Алекс Селбі

Відповіді:


11

На ваше запитання 2 (дефрагментація пам'яті), цитуючи з https://www.kernel.org/doc/Documentation/sysctl/vm.txt :

компактна пам'ять

Доступно лише тоді, коли встановлено CONFIG_COMPACTION. Коли в файл записується 1, всі зони ущільнюються таким чином, що вільна пам'ять є доступною у суміжних блоках, де це можливо. Це може бути важливо, наприклад, при розподілі величезних сторінок, хоча процеси також будуть безпосередньо компактні в пам'яті за потребою.

це означає, що наступна команда (виконується з привілеями root та якщо параметр ядра, згаданий вище, був включений)

echo 1 > /proc/sys/vm/compact_memory

слід сказати ядру намагатися дефрагментацію пам'яті якомога більше. Остерігайтеся, що, наприклад, у деяких версіях RHEL6 це може зламати ядро ​​...


1
Дякуємо, що витратили час, щоб повернутися та прокоментувати старе питання!
OldTinfoil

7

Минуло небагато часу, але я подумав, що не буду відповідати, поки не отримаю відповіді на всі 3 мої підпитання.

Перш ніж розпочати, я зазначу, що правильний термін, що стосується "дефрагментації" робочої пам'яті, називається "ущільненням" робочої пам'яті.

1. Хіба rm не виконується, оскільки не вистачало суміжної оперативної пам’яті?

Я був правильним у своєму висновку - rm не виконував, оскільки не було достатньої суміжної оперативної пам’яті. Система придбала оперативну пам’ять та фрагментувала її, завдяки чому зробила її непридатною.

2. Якщо так, чи існує легкий метод дефрагментації DMA - не вдаючись до перезавантаження системи?

Виявляється, немає можливості ущільнити пам'ять, не маючи можливості перезапустити вбудовану систему. Що стосується системи без MMU, то запобігання - це назва гри.

Частина мене замислюється про те, чи можливо зламати ядро ​​Linux, щоб імітувати MMU в програмному забезпеченні. Я думаю, якби це було можливо, хтось би це вже зробив. Я не уявляю його абсолютно нової концепції;)

3. Як я можу запобігти його в майбутньому?

Для цього проекту я використовував cron, щоб вручну ініціювати програму щоразу, коли це було потрібно. Набагато кращий спосіб зробити це - викликати програму при запуску, а потім змусити програму спати, поки цього не потрібно. Таким чином, пам'ять не потрібно виділяти при кожному використанні. Таким чином, зменшується фрагментація.

Під час першої ітерації проекту ми покладалися на мої виклики сценарію оболонки для виконання критичних функцій (наприклад, rm). Ми не бачили необхідності в тому, щоб переосмислити колесо, якщо цього не потрібно.

Однак я б рекомендував уникати оболонки, де це можливо, для системи без MMU -

( Питання , що станеться, якщо ви стратите ls -la /path/to/directory/ | grep file-i-seek?)

( Відповідь : він запускає новий підпроцес)

Якщо вам потрібно реалізувати частину основних функцій скрипта оболонки у вашій програмі C, рекомендую перевірити вихідний код, який використовується в BusyBox . Можливо, ви будете використовувати C у вбудованій системі.


Дякуємо, що знайшли час повернутися та поділитися своїми висновками.
Калеб

3
[Я усвідомлюю, що це старе] Емуляція MMU складна ... Без MMU кожна програма безпосередньо використовує фізичні адреси, коли вони з'являються на шині пам'яті. Ви можете імітувати його, але вам доведеться перехоплювати кожен доступ до пам'яті (як і фактичний MMU). Виступ був би жахливим. Крім того, ви можете використовувати непрямі покажчики (як це робив Mac OS Classic, називаючи їх "ручками"), але тоді у вас є абсолютно складний API і дуже складний перед випередженням (Mac OS Classic використовував спільну багатозадачність) .
derobert

Дякуємо, що повернулися та витратили час, щоб написати цю відповідь. Я не знав, що класичний MacOS зробив це.
OldTinfoil
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.