7

Linux ベースのサーバーを使用してマルチプレイヤー オンライン ゲームを開発しているプログラマーです。私たちは、私たちの世界に「インスタンス化された」アーキテクチャを使用しています。つまり、ワールド エリアに入る各プレイヤーは、そのエリアのコピーを取得して、同じエリアでプレイしている他のすべてのプレイヤーとは関係なく、パーティ メンバーと一緒にプレイできます。

内部的には、インスタンスごとに個別のプロセスを使用します。最初に各インスタンス プロセスが起動し、特定のエリアに必要なリソースのみを読み込み、ランダムな地形を生成してから、プレイヤーからの新しい接続を許可します。インスタンスによって使用されるメモリの量は、通常、リソースとエンティティでランダムに生成されたレベルを含めて約 25 メガでした。

インスタンスのメモリ フットプリントを削減し、スポーン時間を短縮するために、インスタンスが必要とする可能性のあるすべてのリソース (約 150 MB のメモリ) をロードする単一のマスター インスタンスを作成してから、新しいインスタンスが必要な場合は、fork() 関数を使用して新しいインスタンスを生成し、コピー オン ライト メモリ共有を利用して、新しいインスタンスが「一意の」データ セット用のメモリのみを必要とするようにします。各インスタンスの一意のデータを構成するランダムに生成されたレベルとエンティティのフットプリントは、約 3 ~ 4 MB のメモリです。

残念ながら、メモリ共有は私が思うほどうまく機能していません。多くのメモリ ページが非共有になっているようです。

最初は、より多くのデータ セットをプレフォーク インスタンスにロードすると、フォークされた各インスタンスに必要なメモリが減少しますが、最終的には、プレフォークにより多くのアセットをロードすると、フォークされた各インスタンスによって使用されるデータが実際に増加するという変曲点があります。

私たちが得た最良の結果は、フォーク前に約 80 メガバイトのデータ セットをロードし、その後、新しいインスタンス デマンドに残りをロードさせることです。これにより、インスタンスごとに約 7 ~ 10 メガバイトの余分なメモリと、80 メガバイトの固定コストが発生します。確かに良い改善ですが、理論上の最善ではありません。

150 メガのデータセット全体をロードしてからフォークすると、フォークされた各インスタンスはさらに約 50 メガバイトのメモリを使用します! 単に何もしないよりもはるかに悪い。

私の質問は、すべてのデータ セットを prefork インスタンスにロードし、各インスタンスのメモリ フットプリントとして、インスタンスごとに本当に一意のデータの最小セットのみを取得できるようにする方法です。


私はここで何が起こっているのかについて理論を持っており、誰かがこれが事実であることを確認するのを助けることができるかどうか疑問に思っていました.

それはmallocフリーチェーンに関係していると思います。プリフォーク インスタンスの各メモリ ページには、おそらくメモリの空きスポットがいくつか残っています。ランダム レベルの生成中に、たまたまページ内のフリー スポットの 1 つに収まるものが割り当てられた場合、そのページ全体がフォークされたプロセスにコピーされます。

Windows では、代替ヒープを作成し、プロセスで使用される既定のヒープを変更できます。これが可能であれば、問題は解消されます。Linuxでそのようなことを行う方法はありますか? 私の調査では、あなたにはできないことが示されているようです。

もう 1 つの解決策として、既存の malloc フリー チェーンを何らかの方法で破棄し、malloc にオペレーティング システムから新しいメモリを割り当てさせて、後続の呼び出しに使用させることができます。これが簡単にできるかどうか、malloc の実装を調べてみましたが、やや複雑なように思えました。この分野に関するアイデアや、このアプローチをどこから始めるべきかについての提案があれば、ぜひ聞いてみたいと思います。

最後に、ここで何がうまくいかないのかについて他のアイデアを持っている人がいれば、ぜひ聞いてみたい. どうもありがとう!

4

1 に答える 1

2

Windows では、代替ヒープを作成し、プロセスで使用される既定のヒープを変更できます。これが可能であれば、問題は解消されます。Linuxでそのようなことを行う方法はありますか?

mmap(2)Unixでは、バイパスmallocを完全に記憶することができます。

また、「牛に頼る」こと全体を捨てます。マスターにmmapいくつかのメモリ(80M、150Mなど)を処理させ、それに書き込み、mprotect(2)適切な測定のために読み取り専用としてマークし、そこから取得します。これにより、実際の問題が解決され、将来的にコードを変更する必要がなくなります。

于 2012-03-24T11:04:56.717 に答える