4

JVM で実行するアプリケーション (ゲーム) があります。

ゲームの更新ロジック (毎秒 60 回実行) は、「タイム スライス」 (1/60 秒) の約 25% を使用して終了し、残りの 75% をスリープ状態にします。しかし、GC コレクターが実行されると、75 ~ 200% まで上昇し、残りの実行中はその状態が続きます。

ゲームは約 70Mb のヒープを使用し、約 1-2mb/s で成長します。GC が実行されると 70Mb に戻るため、真のメモリ リークはありません。将来的にはこの数値を下げるように努めますが、この範囲では問題にならないはずです。

ランタイム引数やフラグなしで JVM 8 を使用していますが、どの GC が私に与えるのかわかりません。

ヒープを別のサイズに設定してみましたが、この現象には影響しません。

これがなぜなのかについては、次の 2 つの理論があります。

  1. GC は意図せずにヒープを断片化し、更新ループでキャッシュの破棄を引き起こします。データがループして更新されるため、データの近接性から大きな恩恵を受けるロジックがあります。一部のデータを古い領域にシャッフルし、一部を若い領域 (苗床) に保持している可能性がありますか?

  2. 突然の GC 処理が OS をトリガーし、メインの更新スレッドが現在ほど多くの CPU リソースを必要としないことを OS に認識させ、その優先度を下げます。(ただし、thread.sleep() をスキップして未使用の CPU 使用率からスリープしても現象は持続します。

どう思いますか。私の理論はもっともらしいですか、それらについて何かできることはありますか、それとも C 言語に切り替える必要がありますか? GC に関する私の知識は限られています。

PS 補足として、通常、update() はポスト GC の 75% で終了します。200% のような数値が得られるのは、VSync を使用している場合です。

4

2 に答える 2

1

もう有効ではない:

私はテストを行い、アーキテクチャを完全に台無しにしました。私はこれを持っていましたが、これはアプリケーションのボトルネックでした:

class Physics{
   Vec2 centre;
   Rec hitbox;
   Vec2 speed;
   Vec2 acc;
   ...

   public void update(){ //critical method
       centre.doThings();
       hitbox.doThings();
       etc...
   }

}

そして、プリミティブのみを使用するように変更しました:

class Physics{
   double centreX,centreY;
   double x1,x2,y1,y2;
   double speedX,speedY;
   double accX,accY;
   ...

   public void update(){ //critical method
       implementation of methods above...
       etc...
   }

}

これは、少なくとも Java は、クラス プリミティブ メンバーが宣言された順序で、ヒープのクラス ヘッダーの下に格納されることを保証するためです。オブジェクトへの参照は、ヒープの反対側へのアドレスである可能性があります。

これは、圧縮 GC とともに、キャッシュ ヒットの増加に貢献したと思います。それは私のアーキテクチャを破壊しましたが、それは私が喜んで支払う代償です.

ゲームは安定した 15% で実行されるようになり、自分の投稿を回答としてマークします。

編集: それはただの混乱した男のとりとめのないことでした. 上記はわずかなパフォーマンス向上のみをもたらしました。残りはアプリケーションのバグによるものであり、アーキテクチャの変更を正当化するものではありませんでした。ただし、圧縮GCは少し役立ちました。

于 2016-11-18T17:34:49.233 に答える