Повышение эффективности использования fork() и копирования при записи совместное использование памяти

I Я программист, разрабатывающий многопользовательскую онлайн-игру с использованием ng серверы на базе Linux. Мы используем «экземплярную» архитектуру для нашего мира. Это означает, что каждый игрок, входящий в область мира, получает копию этой области для игры с членами своей группы и независимо от всех других игроков, играющих в той же области.

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

Чтобы уменьшить объем памяти экземпляров и ускорить время создания, мы перешли к подходу, при котором мы создаем один главный экземпляр, который загружает все ресурсы, которые могут потребоваться любому экземпляру (около 150 мегабайт памяти). ), а затем, когда требуется новый экземпляр, используйте функцию fork() для создания нового экземпляра и использования совместного использования памяти с копированием при записи, чтобы новому экземпляру требовалась память только для его «уникального» набора данных. Объем случайно сгенерированного уровня и сущностей, составляющих уникальные данные для каждого экземпляра, составляет около 3-4 мегабайт памяти.

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

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

Наилучшие результаты, которые у нас были, это загрузка около 80 МБ набора данных перед разветвлением, а затем загрузка остальных экземпляров по запросу. Это приводит к дополнительным 7-10 мегабайтам на экземпляр и фиксированным затратам в 80 мегабайт. Безусловно, хорошее улучшение, но не лучшее в теории.

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

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


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

Я думаю, это связано со свободной цепочкой malloc. На каждой странице памяти экземпляра prefork, вероятно, осталось несколько свободных участков памяти. Если во время генерации случайного уровня выделяется что-то, что помещается в одно из свободных мест на странице, то вся эта страница будет скопирована в разветвленный процесс.

В Windows вы можете создавать альтернативные кучи и изменять кучи по умолчанию, используемые процессом. Если бы это было возможно, это сняло бы проблему. Есть ли способ сделать что-то подобное в линуксе? Мои расследования показывают, что вы не можете.

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

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

7
задан Negs 24 March 2012 в 11:02
поделиться