OutOfMemoryエラーが解決できない
Posted: 2013年4月06日(土) 20:53
こんばんは。
前回Androidのゲーム開発について質問させてもらった者です。
色々なサイト等巡ってみましたが、どうしてもOutOfMemoryエラーが解決できなかったのでここで質問させていただきます。
MenyActivity初回起動時:メモリ使用率85%
↓
HowToPlayActivity起動時:メモリ使用率52%
↓
MenyActivity再起動時:メモリ使用率65%
↓
GameMainActivity起動時:メモリ使用率65%
↓
MenyActivityを起動しようとするとOutOfMemoryで落ちる
となってしまいます。
どのアクティビティ移行時も、メモリ使用率が90%以上になります。
前回ご指摘いただいたように、onStart、onStop時にBitmapの読み込み、解放を行うようにしています。
そのほかにstaticの使用率を減らしたり等いろいろと試みたのですが、どうしても上のタイミングでOutOfMemoryが発生してしまいます。
個人的にはMenyActivity初回起動時のメモリ使用率が異様に高いのが気になっている(GCを走らせてもこのまま、Bitmapやオブジェクトの数はGameMainActivity>>>MenyActivity>HowToPlayActivity)
一度MenyActivityのBitmapを全く読み込まずに起動させてみたところ、同様のエラーが出たためBitmapが原因ではないとは思うのですが・・・
以下がMenyActivityの全貌となります。
長くなってしまい申し訳ありませんが、以上のコードになにかメモリの無駄遣いな点がありましたら教えていただけるとありがたいです。
また、OutOfMemoryが起こったことのある方で、どのように対処したか覚えている方がいらっしゃいましたらぜひその時の対処法を教えてください。
よろしくお願いいたします。
前回Androidのゲーム開発について質問させてもらった者です。
色々なサイト等巡ってみましたが、どうしてもOutOfMemoryエラーが解決できなかったのでここで質問させていただきます。
MenyActivity初回起動時:メモリ使用率85%
↓
HowToPlayActivity起動時:メモリ使用率52%
↓
MenyActivity再起動時:メモリ使用率65%
↓
GameMainActivity起動時:メモリ使用率65%
↓
MenyActivityを起動しようとするとOutOfMemoryで落ちる
となってしまいます。
どのアクティビティ移行時も、メモリ使用率が90%以上になります。
前回ご指摘いただいたように、onStart、onStop時にBitmapの読み込み、解放を行うようにしています。
そのほかにstaticの使用率を減らしたり等いろいろと試みたのですが、どうしても上のタイミングでOutOfMemoryが発生してしまいます。
個人的にはMenyActivity初回起動時のメモリ使用率が異様に高いのが気になっている(GCを走らせてもこのまま、Bitmapやオブジェクトの数はGameMainActivity>>>MenyActivity>HowToPlayActivity)
一度MenyActivityのBitmapを全く読み込まずに起動させてみたところ、同様のエラーが出たためBitmapが原因ではないとは思うのですが・・・
以下がMenyActivityの全貌となります。
public class MenuActivity extends Activity {
private MenuView _menuView;
private PointF touchPt = new PointF();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//画面のタイムアウト防止
_menuView = new MenuView(this);
setContentView(_menuView);
}
@Override
protected void onStart() { // アクティビティが動き始める時呼ばれる
super.onStart();
_menuView.setMemory(getResources());
}
@Override
protected void onStop() { // アクティビティが動き始める時呼ばれる
super.onStop();
_menuView.releaseMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
_menuView.setBackgroundDrawable(null);
_menuView = null;
}
@Override
public boolean onTouchEvent( MotionEvent event )
{
// タッチした位置を取得
touchPt.x = event.getX();
touchPt.y = event.getY();
switch( event.getAction() ){
case MotionEvent.ACTION_DOWN:
switch(_menuView.touchScreen(touchPt)) {
case 1:
gameStart();
break;
case 2:
goHowTo();
break;
case 3:
applicationFinish();
break;
}
break;
}
return true;
}
// ゲームスタート(ゲームメインActibityに遷移)
private void gameStart(){
Intent intent = new Intent( this, DecoyMouseActivity.class );
intent.setAction( Intent.ACTION_VIEW );
startActivity( intent );
}
// 操作説明画面に移動(HowToActibityに遷移)
private void goHowTo(){
Intent intent = new Intent( this, HowToActivity.class );
intent.setAction( Intent.ACTION_VIEW );
startActivity( intent );
}
//
private void applicationFinish(){
finish();
}
}
public MenuView(Context context) {
super(context);
getHolder().addCallback(this);
cnt=0;
rctVd = new Rect(0, 0, Config.VD_WIDTH, Config.VD_HEIGHT);
r_start = new Rect((int)(240-60*1.3), (int)(525-25*1.3), (int)(240+60*1.3), (int)(525+25*1.3));
r_howto = new Rect(110-60, 580, 110+60, 580+50);
r_exit = new Rect(365-60, 580, 365+60, 580+50);
paint.setTextSize(20);
paint.setColor(Color.BLACK);
paint_rect.setColor(Color.RED);
paint_rect.setStyle(Style.STROKE); //枠組みのみ表示
GameScore _gameScore = new GameScore(context);
allscore = _gameScore.getScore();
for(rankcnt=0; rankcnt<Config.RANKNUM; rankcnt++) {
if(allscore < Config.RANKUPSCORE[rankcnt]) break;
}
}
@SuppressLint("WrongCall")
@Override
public void run() {
while (_thread != null) { //メインループ
try{
cnt++;
if(cnt%300<180) mouseState=0;
else if(cnt%300<240) mouseState=1;
else mouseState=2;
onDraw(getHolder());
}catch(NullPointerException e){
}
}
}
private void onDraw(SurfaceHolder holder) {
try{
// 仮想画面の下地を生成
Canvas canvas = new Canvas(imgVdGame);
canvas.drawColor(Color.WHITE); // 白で塗りつぶす
//タイトル
rcSrc.set(0, img_tytle.getHeight()/3*(cnt/8%3), img_tytle.getWidth(), img_tytle.getHeight()/3*(cnt/8%3+1));
rcDst.set(0, 30, 480, 250);
canvas.drawBitmap(img_tytle, rcSrc, rcDst, null);
(以下同様の描画)
//surfaceCreated()が実行されていないと、holder.lockCanvas()はnullを返す
Canvas c = holder.lockCanvas();
// 背景を塗りつぶし
c.drawColor(Color.BLACK);
// 生成したbmp(仮想画面)を画面に表示
c.drawBitmap(imgVdGame, rctVd, rctRd, null);
holder.unlockCanvasAndPost(c);
}catch(NullPointerException e){}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// 仮想画面と実画面の比率を算出
float mult_width = (float)Config.VD_WIDTH / (float)width;
float mult_height = (float)Config.VD_HEIGHT / (float)height;
// 実画面のサイズに引き延ばす辺(幅または高さ)を判断する
if(mult_width < mult_height){
mult = mult_height;
} else{
mult = mult_width;
}
// 仮想画面を拡大して張り付ける実画面上の座標を算出する
int x2=(int)((float)Config.VD_WIDTH / mult);
int y2=(int)((float)Config.VD_HEIGHT / mult);
int x1=(int)((float)width / (float)2 - (float)x2 / (float)2);
int y1=(int)((float)height / (float)2 - (float)y2 / (float)2);
x2 += x1;
y2 += y1;
// 実画面の座標を記録
rctRd = new Rect(x1, y1, x2, y2);
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
_thread = new Thread(this); //別スレッドでメインループを作る
_thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
_thread = null;
}
public int touchScreen( PointF touchPt )
{
if(DiagramCalcr.isHitPR(touchPt, DiagramCalcr.remakeRect(r_start, rctRd.left, rctRd.top, mult))){
// ゲームをスタート
return 1;
}else if(DiagramCalcr.isHitPR(touchPt, DiagramCalcr.remakeRect(r_howto, rctRd.left, rctRd.top, mult))){
// 操作説明画面を開く
return 2;
}else if(DiagramCalcr.isHitPR(touchPt, DiagramCalcr.remakeRect(r_exit, rctRd.left, rctRd.top, mult))){
// このアプリを終了させる
return 3;
}
return 0;
}
public void setMemory(Resources r) {
imgVdGame = Bitmap.createBitmap(Config.VD_WIDTH, Config.VD_HEIGHT, Bitmap.Config.ARGB_8888);
img_tytle = BitmapFactory.decodeResource(r, R.drawable.tytle);
(以下略)
}
public void releaseMemory() {
releaseBitmap(imgVdGame);
releaseBitmap(img_tytle);
(以下略)
}
private void releaseBitmap(Bitmap b) {
if (b != null) {
b.recycle();
b = null;
}
}
}
また、OutOfMemoryが起こったことのある方で、どのように対処したか覚えている方がいらっしゃいましたらぜひその時の対処法を教えてください。
よろしくお願いいたします。