起動時に大量のメモリを割り当てて解放すると、「メモリをクリーンアップしますか?」


18

ブックコンプリート、第4版コーディングゲーム、第5章(ゲームの初期化およびシャットダウン)、セクションのメモリーをチェックするには、この興味深いコードサンプルが含まれています。

bool CheckMemory(const DWORDLONG physicalRAMNeeded, const DWORDLONG virtualRAMNeeded)
{
    MEMORYSTATUSEX status; 
    GlobalMemoryStatusEx(&status);
    if (status.ullTotalPhys < physicalRAMNeeded) 
    {
        // you don’t have enough physical memory. Tell the player to go get a 
        // real computer and give this one to his mother. 
        GCC_ERROR("CheckMemory Failure: Not enough physical memory."); 
        return false;
    }
    // Check for enough free memory.
    if (status.ullAvailVirtual < virtualRAMNeeded) 
    {
        // you don’t have enough virtual memory available.
        // Tell the player to shut down the copy of Visual Studio running in the 
        // background, or whatever seems to be sucking the memory dry. 
        GCC_ERROR("CheckMemory Failure: Not enough virtual memory.");
        return false;
    }

    char *buff = GCC_NEW char[virtualRAMNeeded]; 
    if (buff)
    {
        delete[] buff;
    }
    else
    {
        // even though there is enough memory, it isn't available in one
        // block, which can be critical for games that manage their own memory 
        GCC_ERROR("CheckMemory Failure: Not enough contiguous memory."); 
        return false;
    }
}

これはいくつかの質問を提起します。

最初の部分は、OS(Windows)に使用可能な物理RAMの量を尋ねるだけです。好奇心が強い部分は2番目の部分で、メモリの巨大なチャンクを割り当ててすぐに解放します。

char *buff = GCC_NEW char[virtualRAMNeeded]; 
if (buff)
{
    delete[] buff;
}

著者は続けて説明します:

...この関数は、巨大なメモリブロックを割り当ててすぐに解放します。これにより、Windowsがメモリマネージャーに蓄積されたガベージをクリーンアップし、必要に応じて連続したブロックを割り当てることができるダブルチェックを行うことができます。呼び出しが成功すると、基本的にシステムのメモリを介してZamboniマシンに相当するものを実行し、ゲームが氷にぶつかる準備を整えます...

しかし、私はそれに留保しています。

「メモリマネージャに蓄積されたガベージをクリーニングしますか?」本当に?ゲームが始まったばかりの場合、ゴミはありませんか?

「連続したブロックを割り当てることができますか?」あなたが自分でメモリを管理しようとする非常に特殊なケースでは、これは理にかなっていますが、バットのすぐ右側に多くのメモリを割り当てると、他のアプリケーションを実行することはほとんど不可能になりますあなたのものがオンの間にシステム。

また、これによりOSがそのすべてのメモリをコミットするように強制され、結果としてスワップディスク領域に大量のメモリが追い出され、アプリの起動が大幅に遅くなることはありませんか?

これは本当に良い習慣ですか?


3
最近のほとんどのOSは、全く何もアプリがメモリの大きな領域を割り当てたとき、彼らは楽観的な配分を使用して、メモリを埋めるまで、実際には何もしないもしないだろう、私はより多くの潜在的に遅い無操作されていないよりも、このことは何を想像することはできません
Vality

ジャングルの長い地面を片付けたり、ラジオやヘッドフォンなどを木で切ったりすると、飛行機が着陸し、物資を配達しますか?
ダンニーリー14

10
Game Coding Completeに、多くの理解できないC ++およびC-that-looks-a-bits-like-a-C ++とペアになったナンセンスがたくさん含まれています(このサンプルでも、operator newfor の結果を確認しnullptrます)。言う。その本でできることは、煙突を軽くすることです。もちろん、メモリの大きなブロックを割り当てて解放しても、メモリは「クリーンアップ」されません
デイモン14

@Damon、私はチェックしませんでしたが、私は彼らが少なくともnewスローする代わりにnullを返すようにグローバル演算子をオーバーロードしたと思われますbad_alloc。そうでない場合、はい、このコードはさらに無意味です:P
glampert 14

1
@glampert:その場合でも、それをノーオペレーションとしてoperator delete受け入れnullptrて扱う必要があります。それをしないグローバルなオーバーロードは壊れています。つまり、どちらの方法でも無意味です。巨大なメモリブロックを割り当てて解放すると、「魔法のように」何か良いことができると仮定するのと同じです。せいぜい、それは何の害も与えません(おそらく、ページが触れられないので...そうでなければ、後でリロードする必要がある作業セットからいくつかのページをスワップアウトするかもしれません)。
デイモン14

回答:


12

メモリの大きな塊が事前に割り当てていることの一つができませんが、コンピュータはRAM上の低いものであった場合は、ディスクに他のプログラムのメモリ空間の一部を交換することにより、いくつかの余分なスペースを解放するためにOSを強制するかもしれません。

このようなスワッピングは一般的に非常に遅い操作であるため、プログラムの実行中はほとんどフリーズするので、とにかく発生する場合は、ゲームプレイの途中ではなくゲームの開始に発生するようにすることには、いくつかの利点があります。

ただし、このようなディスクへのスワップを強制することは、完全に100%信頼できるわけではありません。

  • 多くの仮想メモリの実装では、単にメモリを割り当てるだけでは実際にはスワッピングがトリガーされません。むしろ、割り当てたメモリの各ページに最初にアクセスしたときにのみ発生します。(これは、デフォルトでメモリオーバーコミットが有効になっているLinuxの最新バージョンでは確かに当てはまります。Windowsの異なるバージョンがどのように処理するかはわかりません。)

    したがって、このコードで「メモリをクリーンアップ」したい場合は、memset()呼び出しまたは同等のものを追加して、実際に配列のすべての部分(または少なくとも最初のphysicalRAMNeededバイト)に実際にデータを書き込む必要があります。

  • また、OSがこのようにRAMから他のプログラムを強制的にスワップすることは、それらがそこに留まることを意味しません。WindowsはマルチタスクOSであり、スワップアウトされたプログラムの1つが再び実行され、スワップアウトされたデータを使用するとすぐに、スワップインされ、ゲームが再びフリーズする可能性があります。

    したがって、このトリックは通常、アクティブにアクセスされていない大きなデータチャンク(一部の編集ソフトウェアでバックグラウンドで開いている大きなドキュメントなど)がRAMを食い尽くしている場合にのみ役立ちます。Webブラウザは、この点で特に問題が発生しやすい傾向があります。実際には、バックグラウンドタブで開かれたWebページを実際に使用していない場合でも、ページにはRAMを保持するスクリプトが実行されている可能性があるためです。

    (存在している実際にRAMにそのメモリ空間の一部をロックして、スワップアウトされることを防ぐために、OSを指示するプログラムのための方法は、これらは一般的に上昇する権限が必要です。いずれにせよ、あなたが投稿したコードがあるようには見えませんそのような方法を使用します。)

基本的に、このトリックは、ユーザースワップせずにゲーム(およびバックグラウンドでアクティブに実行されている他のソフトウェア)を実行するのに十分なRAMを持っている比較的狭い境界線の状況でのみ役立つようですが、RAMは現在、非アクティブで未使用のオープンファイルでいっぱいですまたは、ゲームの実行中にディスクに交換できる、または交換すべきその他のデータ。このような状況では、ゲームプレイ中に時々起こる小さなスワップ操作を起動時の単一の操作に置き換えることにより、ゲームをよりスムーズで応答性のあるものにするのに効果的です。


1
低レベルのメモリ管理に関する私の限られた知識から、特定のページをスワップするかどうかの決定ははるかに複雑であり、単に要求されたメモリの量と利用可能なメモリの量よりも多くの要因を考慮に入れることができます。これを過度に単純化し、一般的に仮定に頼ることはあまり賢明ではありません。
パンダパジャマ14

3
これらはすべて、動作しない、動作しない、または動作しているように見えるが、完全に無関係な理由であるという仮定であることに留意することが重要だと思います。私の知る限り、この回答で指摘されている行動はいずれも文書化されておらず、それらに依存するのは賢明ではありません。OSの更新、設定の変更、コンパイラーの変更など、これが機能しなくなるか、パフォーマンスに悪影響を及ぼす可能性があります。
パンダパジャマ14

26

私はその記事が何歳かは知りませんが、かなり古いと思います。最新のWindows(XP以降、特に64ビットバージョン)では、そのようなことを行っても、ゲームの起動にほとんど影響はありません。

まず、プロセスごとにアドレス空間が仮想化されていることを忘れないでください。プロセスに関する限り、アドレス空間はすべて自分自身にあり、メモリが物理的に連続しているかどうかに関係なく、常に連続した(仮想)メモリを取得します。

実際、物理メモリ内でメモリが連続しているかどうかは、ユーザーが制御できるものではありません。OSは適切と思われる物理ブロックの割り当て方法を選択します。アプリケーションレベルで行うことは、物理メモリが連続していることの利点(ある場合)に影響を与えることはできません。

非常に長い時間、さまざまなサイズのメモリの割り当てと解放を続ける場合、仮想メモリの断片化に注意する必要があります。もちろん、これは64ビットのアドレス空間ではあまり重要ではありません。通常、ゲームは数か月間実行されないため、長時間実行されるゲームサーバーについて説明している場合を除き、これを気にする必要はほとんどないでしょう。

32ビットマシンで大幅に異なるサイズの多くのメモリを割り当てたとしても、最新のメモリ割り当てはかなり良いので、積極的に探しているのでなければ仮想メモリの断片化の問題は発生しません

正直に言うと、その作家が何をしているのかわかりません。アドレス空間が共有されていて、物理メモリに巨大な連続したブロックを取得したとしても、それを解放することで、それをもう気にしないと言っています。バックグラウンドで実行されている他のプログラムが独自の割り当てを行っているため、巨大なmallocが成功したとしても、次のプログラムが同様に成功することを保証する人はいません。

これは「何らかの理由でうまく理解できなかったので、それを説明するために何かを作り上げた」と思う。


10
RAMは、連続したブロックを持つことが、決して「より良い」という点で、回転するハードディスクのようなものではありません。 本当じゃない。連続RAMアクセスは、ランダムアクセスよりも桁違いに高速です。RAMチップは、切り替えに一定の遅延があるセクションに分割されます。さらに重要なことに、L1およびL2キャッシュミスは、メモリが分散している場合にパフォーマンスに大きく影響します。
キャプテンコードマン14

@CaptainCodeman:私の知識の範囲外になることを受け入れなければなりませんが、Windowsのアプリケーションプログラマーとしては、メモリが物理的に連続しているかどうかを制御することはできません。巨大なメモリブロックを要求しても、それほど変わりません。
パンダパジャマ14

@CaptainCodemanは、実際には、RAM内の連続mod 2 ^ Nブロックに連続仮想ブロックがあるため、キャッシュラインの割り当てにより高速化されます
ラチェットフリーク14

8
@CaptainCodemanええ、シーケンシャルDRAMアクセスは高速ですが、4 KB(またはそれ以上)のページで発生する仮想->物理マッピングについて話しているので、そのマッピングがシーケンシャルであるかどうかはメモリに大きな影響を与えません読み取り速度。さらに、キャッシュのプリフェッチなどは、物理アドレスではなく仮想アドレススペースで動作します。
ネイサンリード14

1
@NathanReedフェア、そして説明をありがとう。提案されたように、RAMアクセス速度がメモリ空間全体で完全に均一ではないことを単に表現していました。
キャプテンコードマン14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.