Як я можу обмежити об'єм пам'яті, доступної для процесу?


11

Я розробляю програму по ходу; вона періодично закінчує виділення дуже великої кількості пам’яті (>> 10G на машині з 8G фізичної пам’яті), внаслідок чого система не реагує. Я хочу обмежити об'єм пам'яті, який процес може виділити. Звичайний спосіб я це зробив:

ulimit -m 4000000 ; ./myprogram

... що повинно вбити мою програму, якщо вона намагається використовувати більше 4 Гб пам'яті.

Для OS X El Capitan це, мабуть, не впливає; навіть ulimit -m 1(обмеження всіх програм лише 1 кБ пам'яті!) неефективно.

Як я можу встановити верхню межу пам'яті, доступної для певного процесу?


Коли ви говорите "Звичайний спосіб, як я це зробив би" , що ви маєте на увазі? Більш конкретно, коли ти зазвичай робиш це? І коли ви це робите, ви маєте на увазі в Mac OS X El Capitan або в іншому середовищі? Чи можете ви навести приклад того, коли ви його успішно використовували? В основному я просто намагаюся уточнити, чи нормально працює цей процес для вас, але просто не працює для цієї конкретної програми? Або це взагалі не працює для вас, але ви вважаєте, що це повинно?
Мономет

1
"Звичайним способом я б це робив", я маю на увазі так, як я би робив це для інших ароматів unix. Зауважу, що я щойно виявив, що ulimit -mбільше не працює в Linux (> 2.4.30), хоча ulimit -vвсе ще працює так, як очікувалося. (Мовляв ulimit -m, ulimit -vтакож, здається, це не впливає на OS X.)
cpcallen

Це здається, що у програмі, про яку ви пишете, у вас витік пам'яті і вам потрібно покращити збирання сміття. Чи читали ви про управління пам’яттю в дорозі?
Тодд Дабні

1
Ні, не витік пам'яті - лише пошук графіка потенційно дуже великого простору стану. Я міг би додати код для припинення пошуку, якщо різні внутрішні структури стануть занадто великими, але я очікував, що зможу зробити те ж саме (не дозволяти машині вклинюватися великими входами) за допомогою одного вкладиша оболонки.
cpcallen

Відповіді:


1

Існує два підходи до обмеження використання вашої пам’яті: Ex post facto та превентивний. Тобто ви можете спробувати вбити свою програму після того, як вона стала занадто великою, або ви можете запрограмувати її, щоб вона не стала занадто великою.

Якщо ви наполягаєте на підході ex post facto, ви можете використовувати наступний сценарій Bash. Цей скрипт спочатку знаходить об'єм пам'яті (як визначено "розміром резидентного набору"), який використовує процес із процедідним pid, фільтрує всі нечислові дані за допомогою grep та зберігає кількість як змінну n. Потім сценарій перевіряє, чи n більший за вказаний х. Якщо це так, процес із процедидом pid вбивається.

Будь ласка, запиши:

  1. Ви повинні замінити <pid>ідентифікатор процесу вашої програми.
  2. Ви повинні замінити <x>на rss = "розмір постійного набору" (тобто реальний розмір пам'яті), який ви не хочете, щоб програма перевищувала.

n=$(ps -<pid> -o rss | grep '[0-9]') if [ $n -gt <x> ]; then kill -9 <pid>; fi

Якщо ви хочете, щоб це працювало кожні y секунди, просто вкладіть його у цикл і скажіть, щоб він чекав y секунди після кожної ітерації. Ви також можете написати подібну команду, використовуючи top. Вашою відправною точкою буде top -l 1|grep "<pid>"|awk '{print $10}'.

@ Kenorb в відповідь допоміг мені з моїм сценарієм


Хоча я вважаю, що це відповідає на це питання, але, зрештою, я вважаю, що краще розробляти програмування, щоб використовувати переважний підхід із використанням ручного розподілу пам'яті.

По-перше, ви впевнені, що використання пам'яті справді є проблемою? У документації Go зазначено:

Розподільник пам'яті Go залишає велику область віртуальної пам'яті як арену для розподілу. Ця віртуальна пам'ять є локальною для конкретного процесу Go; застереження не позбавляє інших процесів пам’яті.

Якщо ви все ще вважаєте, що у вас є проблеми, я рекомендую вам вручну керувати своєю пам'яттю, як це робиться на мові програмування C. Оскільки go написано на C, я підозрював, що знайдуться способи потрапити в управління / розподілу пам'яті C, і справді вони є. Перегляньте це сховище github, яке,

дозволяє здійснювати ручне управління пам’яттю через стандартний розподільник C для вашої системи. Це тонка обгортка зверху мальлока, калька та вільна від неї. Детальну інформацію про ці функції для вашої системи дивіться у manloc. Ця бібліотека використовує cgo.

Випадок використання подається у вигляді:

Чому б ти цього хотів?

Коли програма викликає тиск у пам’яті або в системі не вистачає пам’яті, це може бути корисно вручну керувати розподілом пам’яті та переміщенням. Go може допомогти вам контролювати асигнування, але неможливо чітко розмістити непотрібні дані.

Це здається кращим довгостроковим рішенням.

Якщо ви хочете дізнатися більше про C (включаючи управління пам'яттю), мова програмування C є стандартною базою.


Я впевнений, що використання пам'яті - це справді проблема. Коли програма несподівано зросла до> 2х фізичного розміру пам'яті, машина стала майже повністю невідповідною через обмолотування сторінки. Минуло близько години, коли я натиснув ^ C і коли macOS відновився у відповідь на клацання миші; тим часом єдиним доказом того, що він не замерз, був тихий шум жорсткого диска, який швидко тикав.
cpcallen

Це, мабуть, розумне рішення на практиці, але на відміну від ulimit на (не дарвінських) ОС UNIX, це залежить від можливості вчасно виділити достатню кількість пам'яті для успішного виконання команди kill. Я дійсно вважаю, щоб ядро ​​застосовувало обмеження розміру процесу.
cpcallen

@cpcallen, виконуючи деякі пошуки, здається, що "-m параметр ulimit не впливає на системи Linux із версіями ядра останніх, ніж 2.4.30." Здається, OSX також прийняла цю зміну. Спробуйте варіант -v обмежити адресний простір
Evan Rosica

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