【Android】JavaのGCの発生を抑えたい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
奥兵

【Android】JavaのGCの発生を抑えたい

#1

投稿記事 by 奥兵 » 10年前

AndroidでOpenGLESでシューティングゲームを作成しているのですがGCによるカクツキを無くせなくて困っています。
Webを参考にDDMSの割り当てトラッカーを使って、自分の書いたクラスの毎ループ確保されるローカル変数をなくして、微改善はしたのですが
それでも2~5秒程度の間隔でGCが発生して、ときどき(だいたい10~15秒に一回程度)カクついてしまいます。

割り当てトラッカーを見ているとどうも、描画用メソッドでメモリが繰り返し確保されており、多分そこが原因と思うのですが、問題の根本も対処法も検討がつきません。
アドバイスの程お願いします。

↓描画用のメソッド トラッカーで怪しそうだったのはコメントに矢印のある部分です

コード:

public void draw( GL10 gl, int id ){

		gl.glBindTexture(GL10.GL_TEXTURE_2D, texMap.get(id));//// ← 
	    //-------------------------------------------------------------
	    //テクスチャ座標の位置とデータを指定
	    // 位置情報 uvは左上が(0,0)
	    // ※本当は左下が(0,0)だが画像が上下ひっくり返る為、左上が(0,0)と考える

	    bbuv = ByteBuffer.allocateDirect(uv.length * 4);//// ← 
	    bbuv.order(ByteOrder.nativeOrder());
	    fbuv = bbuv.asFloatBuffer();//// ← 
	    fbuv.put(uv);//// ← 
	    fbuv.position(0);
	    
	    // テクスチャバッファの成分を有効にする。
	    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
	    // 1.要素数uv 2つ
	    // 2.Bufferが格納されている型の指定
	    // 3.第一引数を読み込んだ後、読み込みをスキップする数
	    // 4.値が格納されているバッファの指定
	    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, fbuv);
	    
	    //-------------------------------------------------------------
	    
	    // ! 位置情報
//	    float positions[] = {
//	    		pos_x				,pos_y					,0,
//	    		pos_x				,pos_y+(height*scale)	,0,
//	    		pos_x+(width*scale)	,pos_y					,0,
//	    		pos_x+(width*scale)	,pos_y+(height*scale)	,0	    		
//	    };
	    //↓GC対策として
	    positions[0] = pos_x;					positions[1] = pos_y;					positions[2] = 0;
	    positions[3] = pos_x;					positions[4] = pos_y+(height*scale);	positions[5] = 0;
	    positions[6] = pos_x+(width*scale);		positions[7] = pos_y;					positions[8] = 0;
	    positions[9] = pos_x+(width*scale);		positions[10] = pos_y+(height*scale);	positions[11] = 0;
	    
	    
	    // ! OpenGLはビッグエンディアンではなく、CPUごとの
	    //ネイティブエンディアンで数値を伝える必要がある。
	    // ! そのためJavaヒープを直接的には扱えず、
	    //java.nio配下のクラスへ一度値を格納する必要がある。
	    bb = ByteBuffer.allocateDirect(positions.length * 4);//// ← 
	    bb.order(ByteOrder.nativeOrder());
	    fb = bb.asFloatBuffer();//// ← 
	    fb.put(positions);
	    fb.position(0);
	
	    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
	    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, fb);
	    // 1.モード(GL_TRIANGLE_STRIP:連続した三角形)
	    // 2.何番目の頂点から描画を行なうかを指定
	    // 3.いくつの頂点を利用するかを指定
	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
	   // gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
	    
	}

LL

Re: 【Android】JavaのGCの発生を抑えたい

#2

投稿記事 by LL » 10年前

使ったことはないので、いくらかトライアンドエラー覚悟で実験する必要性があると思いますが、
java.lang.Runtimeクラスのgc()メソッドで任意のタイミングによるガベージコレクションをすることが出来るようです。

参考サイト
http://www.booran.com/menu/java/garbagecollection.html

http://docs.oracle.com/javase/jp/6/api/ ... ntime.html

ISLe()

Re: 【Android】JavaのGCの発生を抑えたい

#3

投稿記事 by ISLe() » 10年前

Float Bufferを最初に一回作って使い回せば良いのでは。

コード:

bb = ByteBuffer.allocateDirect([最大サイズ]);
bb.order(ByteOrder.nativeOrder());
fb = bb.asFloatBuffer();
これを最初に一回だけやって、fbを覚えておく。

コード:

fb.position(0);
fb.put([配列名]);
fb.position(0);
従来の箇所はこうする。

奥兵

Re: 【Android】JavaのGCの発生を抑えたい

#4

投稿記事 by 奥兵 » 10年前

アドバイスありがとうございます。ご指摘いただいた部分を修正して、毎ループのメモリの確保をだいぶ減らせました。
ただ、まだカクツキがありdrawメソッドの最初の行の

コード:

gl.glBindTexture(GL10.GL_TEXTURE_2D, texMap.get(id));
がメモリを確保しています。
いろいろ調べてみると、glBindTextureは遅いと評判のようです。一枚のテクスチャに画像を纏めたテクスチャアトラスなるものを使うといいらしいとのことです。
HashMapは宣言部分で初期化しているのでこちらのほうが怪しいような気がします。
メモリの確保の原因がglBindTextureかどうかは疑わしいですが、調べてみてそれらしい感じだったらテクスチャアトラスの実験してみようと思います。

ISLe()

Re: 【Android】JavaのGCの発生を抑えたい

#5

投稿記事 by ISLe() » 10年前

テクスチャを頻繁に切り替えると遅くなるのはAndroidだとかOpenGLだとかに限らないので、glBindTextureが特別遅いわけではないのではないでしょうかね。
テクスチャをまとめて切り替えを減らし高速化すると、GCが減らずとも、GCが気にならなくことはあるかもしれません。

わたしはHashMapのような重いコンテナはそもそも使わないので、そこの影響は分かりません。
JavaSE SDKのソースを見る限りでは、getメソッドを呼ぶだけでもけっこう大量のローカルオブジェクトを生成するようです。

奥兵

Re: 【Android】JavaのGCの発生を抑えたい

#6

投稿記事 by 奥兵 » 10年前

今、下のように変更して実験してみたところ割り当てトラッカーが示したのはHashMapのほうでした。
犯人はHashMapのほうでした、これから対策を調べなおして考えてみます。

コード:

int  texId = texMap.get(id);
gl.glBindTexture(GL10.GL_TEXTURE_2D, texId);

奥兵

Re: 【Android】JavaのGCの発生を抑えたい

#7

投稿記事 by 奥兵 » 10年前

ごめんなさい、一個前の投降は間違いです。忘れてください。

奥兵

Re: 【Android】JavaのGCの発生を抑えたい

#8

投稿記事 by 奥兵 » 10年前

連投すいません。解決いたしましたので報告させていただきます。
まずISLe()さんに、教えていただいた部分を修正して、GCはほぼ起こらなくなりました。
まだ残っていたカクツキは、発射音用に試験的に最近組み込んだmSoundPool.play()が原因でした。
コメントアウトするとスムーズに動作しました。
アドバイスありがとうございました。とても助かりました。多謝です。

ISLe()

Re: 【Android】JavaのGCの発生を抑えたい

#9

投稿記事 by ISLe() » 10年前

HashMapの名誉のために補足します。

HashMap#getのソースコードをきちんと追跡したところ、複雑な処理をしてはいますが、新たなオブジェクトの生成は行われていないことを確認しました。
HashMap#getを呼ぶだけではGCに影響はないと思われます。

閉鎖

“C言語何でも質問掲示板” へ戻る