Выделение памяти программе при инициализации в C ++? - PullRequest
1 голос
/ 05 августа 2020

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

Если это невозможно, не могли бы вы направить меня к модулю кучи, который я могу импортировать в мой проект? Использование C ++ 17.

Edit: Более конкретно, я пытаюсь, например, указать, что, например, разрешено только mallo c 4MB данных. Если он пытается выделить больше, он должен выдать ошибку.

Ответы [ 3 ]

2 голосов
/ 07 августа 2020

То, о чем вы спрашиваете, невозможно с функциями, предоставляемыми ISO C ++.

Однако на большинстве распространенных платформ резервирование физической ОЗУ возможно с использованием специфичных для платформы расширений c. Например, Linux предоставляет функцию mlock , а Microsoft Windows предоставляет функцию VirtualLock . Но для того, чтобы использовать эти функции, вы должны либо

  1. знать, какие страницы памяти распределитель по умолчанию использует для выделения памяти, что может быть запутанным и сложным, или
  2. используйте вашу собственную реализацию распределителя памяти, чтобы он мог сам вызывать mlock / VirtualLock всякий раз, когда он получает память от операционной системы.

Ваша собственная реализация памяти распределитель может быть таким же простым, как пересылка всего запроса на выделение памяти в ядро ​​ операционной системы, например, используя mmap на Linux или VirtualAllo c на Windows. Однако это имеет недостаток, заключающийся в том, что степень детализации всех запросов на выделение памяти равна размеру страницы памяти, которая в большинстве систем составляет не менее 4096 байт. Это означает, что даже очень маленькие запросы на выделение памяти размером в несколько байтов фактически займут 4096 байт памяти. Это было бы большой тратой памяти. Кроме того, в своем вопросе вы указали, что хотите предварительно выделить определенный объем памяти при запуске приложения, чтобы вы могли использовать эту память позже для удовлетворения меньших запросов на выделение памяти. Это невозможно сделать с помощью метода, описанного выше.

Следовательно, вы можете рассмотреть возможность использования «правильной» реализации распределителя памяти, которая способна удовлетворить несколько небольших запросов на выделение с использованием одной страницы памяти. См. этот список в Википедии для списка распространенных реализаций.

Тем не менее, то, что вы описываете, может быть проблемой XY , в зависимости от того, какую операционную систему вы используете . Например, в отличие от Windows, Linux обычно приводит к избыточному использованию памяти. Это означает, что ядро ​​Linux позволит приложениям выделять больше памяти, чем фактически доступно, при условии, что большинство приложений не будут использовать всю запрошенную память. Следовательно, вызов std::malloc или new редко завершается ошибкой на Linux (но это все еще возможно, в зависимости от конфигурации ). Вместо этого в условиях нехватки памяти Linux убийца OOM (убийца нехватки памяти) начнет убивать процессы, которые занимают большой объем памяти, чтобы освободить память и поддерживать работу системы. .

По этой причине описанные выше методы, вероятно, будут работать на Microsoft Windows, но на Linux они могут быть контрпродуктивными, так как они сделают ваш процесс более вероятным стать жертвой OOM убийца.

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

0 голосов
/ 07 августа 2020

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

В C ++ каноническим способом сделать это было бы написать реализацию для operator new() и operator delete() (глобальных!), Которые отвечают за фактическое выделение памяти. Сигнатуры функций:

void* operator new (size_t size);
void operator delete (void *pointer);

, и вам нужно будет включить заголовок #include <new>.

Ваша реализация может выполнять свою работу по одному из трех возможных маршрутов:

  • Он выделяет память с помощью функции C malloc() и сразу касается каждой страницы памяти, записывая в нее значение. Это заставляет ядро ​​системы фактически поддерживать область памяти реальной памятью.

  • Оно выделяет память, используя malloc(), и переходит к вызову mlockall(). Это ядерный вариант, когда вам абсолютно необходимо избегать любого разбиения на страницы, включая разбиение на страницы сегментов кода и общих библиотек. переходит к их блокировке в ОЗУ через mlock(). Эффект аналогичен предыдущему варианту, но он нацелен только на память, выделенную для вашей operator new() реализации.

Первый метод работает независимо от ядра ОС, другой два предполагают ядро ​​Linux.

С помощью G CC вы можете выполнить выделение памяти до вызова main() с помощью __attribute__((constructor)).

Написание такого распределителя памяти - не ракетостроение. Если все сделано правильно, это даже не так уж много кода. Однажды я написал реализацию operator new() / operator delete(), которая умещается в 170 строк, включая все мои специальные функции, комментарии, пустые строки и объявление лицензии. Это действительно не так уж и сложно.

0 голосов
/ 07 августа 2020

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

Зачем вам это нужно?

не ваше дело решать, важнее ли ваша программа, чем другие!

Представьте, что ваша программа работает параллельно с какой-то утилитой печати, управляющей принтером. Это обычное явление: я загрузил какой-то длинный PDF-документ (например, несколько сотен страниц, например, стандарт C ++ n3337 ), и я хочу распечатать его на бумаге, чтобы изучить его в поезде, самолете, дома и сделайте пометки карандашом и бумагой. Печать, вероятно, продлится более часа и потребует вычислительных ресурсов (например, на Linux некотором CUPS драйвере принтера, конвертирующем PDF в PCL ). Во время печати я мог бы использовать вашу программу.

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

Оставьте выделение и управление памятью операционной системе вашего пользователя.

Конечно, есть важные исключения из этого правила здравого смысла. Типичный медицинский робот, используемый в нейрохирургии, имеет встроенное программное обеспечение с ограничениями, отличными от программного обеспечения веб-сервера. См. Также черновик отчета. Для Linux прочтите Advanced Linux Programming затем syscalls (2) .

Более конкретно, я пытаюсь чтобы, например, указать, что разрешено использовать только c 4 МБ данных.

Это действительно просто. Некоторые ОС предоставляют возможность ограничивать ресурсы (на Linux см. setrlimit (2) ...). Напишите свою собственную malloc подпрограмму , указанные выше c примитивы для операционной системы, такие как (на Linux) mmap (2) . См. Также this , this и that ответы (все сосредоточено на Linux; адаптируйте их к вашей конкретной операционной системе). Вероятно, вы можете найти реализации malloc с открытым исходным кодом (на github или gitlab ) для вашей конкретной операционной системы. Для Linux посмотрите здесь , затем изучите исходный код glib c или musl-lib c. В C ++ изучите исходный код G CC или Clang (возможно, ::operator new использует malloc)

...