OutOfMemoryError:Bitmapの使い方の問題?

21,113 views
Skip to first unread message

Lisa

unread,
Oct 8, 2010, 5:03:54 AM10/8/10
to 日本Androidの会
はじめまして、Lisaと申します。
私も今アンドロイド開発を勉強中です。

さっそくですが、今メモリ関係の問題で困っています。
LogCatに表示されるエラーはこれです、

java.lang.OutOfMemoryError: bitmap size exceeds VM budget

いろいろと探して見ました。
recycle()やSystem.gc()を使ってみました。
でも同じエラーが表示されます。
私のアプリではBitmapを使ってボタンを押すたびに画像がかわります。
画像はSD Cardから読み込んでいます。
次の用に画像を読み込んで表示しています。

Bitmap imageB;
ImageView imgV;

imageB = BitmapFactory.decodeFile("sdcard/img.png");
imgV.setImageBitmap(imageB);

解放は次のとうりです。

@Override
protected void onPause() {
super.onPause();
imageBG = null;
System.gc();
}

どなたかわかる方、ご教授願えませんでしょうか?

下手な日本語ですみません。m( _ _ )m 私は日本人では御座いません。

Hiroshi SAKURAI

unread,
Oct 9, 2010, 10:04:59 AM10/9/10
to android-g...@googlegroups.com
桜井と申します。

2010/10/8 Lisa <lpk...@gmail.com>:


> java.lang.OutOfMemoryError: bitmap size exceeds VM budget

1. Bitmapが解放されていない
2. Bitmapが大きすぎて、メモリに入らない

の2つの原因が考えられますが、後者だとしたら、
decodeFile(String pathName, BitmapFactory.Options opts)
のopts.inSampleSizeを指定して、間引いてはいかがでしょう?

--
Hiroshi SAKURAI


2010/10/8 Lisa <lpk...@gmail.com>:

> --
> このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
> このグループから退会するには、android-group-j...@googlegroups.com にメールを送信してください。
> 詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。
>
>

Nobuo Kitagawa

unread,
Oct 10, 2010, 2:37:54 AM10/10/10
to 日本Androidの会
北川@comictribes.comです。

BITMAPの大きさの問題の可能性が大きそうですが、
一般的なOOMという観点で、GCで回収できていないメモリ領域がないか、
確認してみることをお勧めします。

eclipseのツールのMemory Analyzerでメモリ確保状態をみることができます。
以下にインストール方法を示します。参考にしていただければ。

http://xiangcai.at.webry.info/201009/article_7.html

Lisa

unread,
Oct 12, 2010, 4:37:24 AM10/12/10
to 日本Androidの会
桜井さん、北川さん、回答ありがとうございました。

Bitmapは表示されます。でも、何回か画像を変えているとエラーが出てきます。
たぶんエラーは、Bitmapを正しく解放していないかと思われます。

なので早速Memory Analyzerをインストールをしました。
でも意味がわからないです。

どうやって見たらいいのでしょうか。
すみません、初心者なので分らない事だらけです。

長井成実

unread,
Oct 12, 2010, 5:03:56 AM10/12/10
to android-g...@googlegroups.com
> imageB = BitmapFactory.decodeFile("sdcard/img.png");
> imgV.setImageBitmap(imageB);

if (imageB != null) {
imageB.recycle();
imageB = null;


}
imageB = BitmapFactory.decodeFile("sdcard/img.png");
imgV.setImageBitmap(imageB);


とするとうまくいくと思います。
新しいイメージを用意する前に、以前のイメージを破棄する感じです。

2010年10月8日18:03 Lisa <lpk...@gmail.com>:

> --
> このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
> このグループから退会するには、android-group-j...@googlegroups.com にメールを送信してください。
> 詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。
>
>

--
====================
Narumi NAGAI
narumi...@gmail.com
====================

Lisa

unread,
Oct 12, 2010, 7:11:02 AM10/12/10
to 日本Androidの会
長井さん 回答有難うございました。

試してみましたがエラーはまだ出てきます。(U_U,)
もうどうすればいいのか分りません。

ImageViewは、bitmapを使ってるのでしょうか。
時々こんなエラーも出るようになりました。

android.view.InflateException: Binary XML file line #23: Error
inflating class java.lang.reflect.Constructor

line 23は、

23: <ImageView
24:  android:id="@+id/imgTest"
25:  android:src="@drawable/ts_bg"
26:  android:layout_width="wrap_content"
27:  android:layout_height="wrap_content"
28:  android:layout_centerHorizontal="true" />
が書かれています。

どうすればいいのでしょうか。

飯塚康至

unread,
Oct 12, 2010, 8:37:14 PM10/12/10
to android-g...@googlegroups.com
こんにちは、飯塚です。

とりあえず
(対策1)
//ARGB_8888,RGB_565,ARGB_4444
Bitmap newBitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.RGB_565);
Config.RGB_565で半分の消費になります。

(対策2)
OptionsのinJustDecodeBoundsをtrueにして読み込み先にサイズを取得する
サイズを調整して読み込む

参考:
http://d.hatena.ne.jp/hdk_embedded/20100518/1274121081
http://www.hoge256.net/2009/08/432.html

2010年10月12日20:11 Lisa <lpk...@gmail.com>:

> --
> このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
> このグループから退会するには、android-group-j...@googlegroups.com にメールを送信してください。
> 詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。
>
>

--
以上、宜しくお願いします。

飯塚 康至

Lisa

unread,
Oct 13, 2010, 8:36:44 PM10/13/10
to 日本Androidの会
飯塚さん、ご回答有難うございました。

試してみたんですけど、エラーは出てきます。(u_u,)

エラーは違う所に有るのでしょうか。

ohisamallc

unread,
Oct 13, 2010, 10:43:17 PM10/13/10
to android-g...@googlegroups.com
山形のohisamaです。
山形では、イナゴ食べます。

このコードで小さくなりますので、試して下さい。

BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inSampleSize=4;
imageB = BitmapFactory.decodeFile("sdcard/img.png", opt);

Lisa

unread,
Oct 14, 2010, 3:12:22 AM10/14/10
to 日本Androidの会
ohisamaさん、ご回答有難うございます。

画像は小さくなりますが、エラーは無くなりません。(u_u,)
エラーは、私が引数としてContextを渡しているからかもしれません。~(・・?)
いろいろと読んでんいたんですけど、多分、私の間違いはこれだと思います。

http://developer.android.com/resources/articles/avoiding-memory-leaks.html

私のcodeは以下です。

//-------------------------------------------------------------
public class ParentActivity extends Activity implements
GenericActivity, OnClickListener {
private UIMediaPlayer mediaPlayer;
private WebView webView;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.layout_episode);

mediaPlayer = (UIMediaPlayer) findViewById(R.id.mediaPlayer);
mediaPlayer.setParent(this);
...
}

public void getPart(current) { ... }
public void loadWebView() { ... }
public WebView getWebView() { return webView; }

}

//-------------------------------------------------------------
public class UIMediaPlayer extends RelativeLayout implements
OnClickListener, Runnable {
private GenericActivity parent;
...

public void init() {
// esatblecemos un layout
LayoutInflater inflater = (LayoutInflater)
this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.media_player, this);

// Obtenermos una referencia a todos los elementos generados en
main.xml
...
mp = new MediaPlayer();
}

public void moveSound(float current) {
parent.getPart(current);
...
parent.loadWebView();
if (visibleText)
parent.getWebView().setVisibility(View.VISIBLE);
...
}
...

}
//-------------------------------------------------------------

どなたかわかる方、ご教授願えませんでしょうか?

Nobuo Kitagawa

unread,
Oct 14, 2010, 4:25:58 AM10/14/10
to 日本Androidの会
北川@comictribes.comです。

やはりリーク系の問題のように思います。
ParentacrivityのonPause でmediaplayer をnullにしてみては
いかがでしょうか。

On 10月14日, 午後4:12, Lisa <lpk...@gmail.com> wrote:
> ohisamaさん、ご回答有難うございます。
>
> 画像は小さくなりますが、エラーは無くなりません。(u_u,)
> エラーは、私が引数としてContextを渡しているからかもしれません。~(・・?)
> いろいろと読んでんいたんですけど、多分、私の間違いはこれだと思います。
>
> http://developer.android.com/resources/articles/avoiding-memory-leaks...

丹羽直也

unread,
Oct 14, 2010, 4:33:15 AM10/14/10
to android-g...@googlegroups.com

sent from Xperia
灘校パソコン研究部-Nada Personal Computer users' Association
Naoya Niwa
MyBlog Mine's Blog: http://mines-blogn.blogspot.com/
Site http://mines.dip.jp/
Twitter: @mine_studio
http://twitter.com/mine_studio

2010/10/14 17:26 "Nobuo Kitagawa" <nob....@gmail.com>:



北川@comictribes.comです。

やはりリーク系の問題のように思います。
ParentacrivityのonPause でmediaplayer をnullにしてみては
いかがでしょうか。


On 10月14日, 午後4:12, Lisa <lpk...@gmail.com> wrote:
> ohisamaさん、ご回答有難うございます。
>

> 画像は小さくなりますが、エラーは無くなり...

> http://developer.android.com/resources/articles/avoiding-memory-leaks...

>
> 私のcodeは以下です。
>
> //-------------------------------------------------------------
> public class ...

丹羽直也

unread,
Oct 14, 2010, 4:34:14 AM10/14/10
to android-g...@googlegroups.com

すいません。
操作ミスでからのメール送ってしまいました。

sent from Xperia
灘校パソコン研究部-Nada Personal Computer users' Association
Naoya Niwa
MyBlog Mine's Blog: http://mines-blogn.blogspot.com/
Site http://mines.dip.jp/
Twitter: @mine_studio
http://twitter.com/mine_studio

2010/10/14 17:26 "Nobuo Kitagawa" <nob....@gmail.com>:


>
> 北川@comictribes.comです。
>
> やはりリーク系の問題のように思います。
> ParentacrivityのonPause でmediaplayer をnullにしてみては...

Lisa

unread,
Oct 14, 2010, 7:52:04 AM10/14/10
to 日本Androidの会
ご回答有難うございます。
onPause でmediaplayer をnullにして見ました。
でも、同じエラーが出てきます。(u_u,)

私もエラーはおしゃるとうりメモリリークだと思います。

if (imageBG != null) {
  imageBG.recycle();
imageBG = null;
}

上記のようにすると、こんどは下記のエラーが出てきます。

10-14 11:36:52.069: ERROR/AndroidRuntime(618): Uncaught handler:
thread main exiting due to uncaught exception
10-14 11:36:52.089: ERROR/AndroidRuntime(618):
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap
android.graphics.Bitmap@437d8e60
10-14 11:36:52.089: ERROR/AndroidRuntime(618): at
android.graphics.Canvas.throwIfRecycled(Canvas.java:955)
10-14 11:36:52.089: ERROR/AndroidRuntime(618): at
android.graphics.Canvas.drawBitmap(Canvas.java:1044)
10-14 11:36:52.089: ERROR/AndroidRuntime(618): at
android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:291)
...

どうしたらいいのでしょうか。
メモリの解放の仕方がわかりません。。゜゜(´□`。)°゜。
どうか教えて下さい。┌(_ _)┐

Takashi Yokoyama

unread,
Oct 14, 2010, 10:00:27 AM10/14/10
to android-g...@googlegroups.com
横山と申します。

経緯がよくわかっていませんので、StackTraceとソースコードから推測しますが、
stackTraceに以下のログが出ていますので、
今回は、「解放済」のBitmapにアクセスしているようです。
別のところで、Canvasにアクセスしていませんか?

もし、Canvasに関する処理がある場合は、描画を回避するように
してみてはいかがでしょうか?

ちなみに、、、recycle済みかどうかは、
Bitmap#isRecycled()で判定可能です。

> java.lang.RuntimeException: Canvas: trying to use a recycled bitmap
> android.graphics.Bitmap@437d8e60

よろしくお願いいたします。

2010年10月14日20:52 Lisa <lpk...@gmail.com>:

> --


> このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
> このグループから退会するには、android-group-j...@googlegroups.com にメールを送信してください。
> 詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。
>
>

--
Takashi Yokoyama
Chugoku GTUG Manager

tksyo...@gmail.com
http://sites.google.com/site/chugokugtug/

ohisamallc

unread,
Oct 14, 2010, 8:41:19 PM10/14/10
to android-g...@googlegroups.com
山形のohisamaです。
山形は、熊が出て大騒ぎです。

意見です。
 このコードの断片見ると、インターフェスとかクラス使って
 ますし、webviewにmediaplayer使ってますが、
 その辺、切り離したコードでテストしてから、組み合わせる
 のが、妥当かと。


自分、クラス嫌いですから。

> > このメールは Google グループのグループ「日本Androidの会」の登録者に送ら

> ています。
> > このグループに投稿するには、android-g...@googlegroups.com にメー

> を送信してください。
> > このグループから退会するには、
> android-group-j...@googlegroups.com にメールを送信してくださ

> 。
> > 詳細については、
http://groups.google.com/group/android-group-japan?hl=ja からこのグループに
アクセスしてください。
>
>

--


Takashi Yokoyama
Chugoku GTUG Manager

tksyo...@gmail.com
http://sites.google.com/site/chugokugtug/

--


このメールは Google グループのグループ「日本Androidの会」の登録者に送られて
います。
このグループに投稿するには、android-g...@googlegroups.com にメールを

宮山

unread,
Oct 15, 2010, 2:33:56 AM10/15/10
to 日本Androidの会
こんにちは、宮山です。

ソースの全体を把握していないので、誤った指摘かもしれませんが、
下記で言う、imageBGはクラス変数とメソッド内の変数のどちらでしょうか?

業務で大量にimageを使ったアプリを作っているのですが、クラス変数に対して
.recycle()をかけても、VMが自分のタイミングを見てメモリを開放するような動きになるようです。

例えば
あるタイミングで、
imageBG.recycle();
imageBG = null;
をして、別のタイミングで
imageBG = new Image();
をすると、
VM側が「自分のタイミング」でrecycle()された変数(この場合はimageBG)に対して
不要なものと判断してGCを行うようで、recylce()メソッド実行後にnewしても、
新たにnewしたかどうか関係なくGC対象と認識して勝手にGCを行ってしまうため、
OOoが発生してしまう現象がありました。

以上の事から.recycle()メソッドは、メソッド内宣言、使用している領域、又はクラスメソッドを保持しているクラスごと
不要になった時に行った方が良いようです。

参考になれば幸いです。

Tatsuo Nagamatsu

unread,
Oct 15, 2010, 3:00:40 AM10/15/10
to android-g...@googlegroups.com
気になったので、ソースコードを見てみました。

Bitmap.recycleは以下のように実装されています。

    public void recycle() {
        if (!mRecycled) {
            nativeRecycle(mNativeBitmap);
            mNinePatchChunk = null;
            mRecycled = true;
        }
    }

http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=graphics/java/android/graphics/Bitmap.java;h=7ca374164096b55ce609d79c1914efc7a5575722;hb=HEAD#l147

nativeRecycleは JNIの実装 Bitmap_recycleを呼び出します。

static void Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) {
    bitmap->setPixels(NULL, NULL);
}


SkBitmapは skiaのライブラリに含まれていて、setPixelsでは現在割り当てられている
Pixelsを解放します。

void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
    this->freePixels();
    fPixels = p;
    SkRefCnt_SafeAssign(fColorTable, ctable);
    SkDEBUGCODE(this->validate();)
}


Pixelsの解放のタイミングは recycleを呼び出したタイミングになっていると思いませんか?

--


2010/10/15 宮山 <mry...@gmail.com>
--

Lisa

unread,
Oct 18, 2010, 12:19:57 AM10/18/10
to 日本Androidの会
ご回答有難うございました。

Canvas: trying to use a recycled bitmap
上記のエラーは出なくなりました。
皆様の情報を参考にいろいろと見たところ、recicleをonStopで使っています。
でも、メモリリークは修正できませんでした。(u_u,)

見たところ、メモリは解放されてると思います。
どうしてかと言うと、私は、
long free = Runtime.getRuntime().freeMemory();
でメモリの動きを見たところ、free memory、が段々増えていくのを確認しました。
でも、こんなエラーが出ます。

10-18 01:44:21.469: DEBUG/dalvikvm(872): GC freed 2855 objects /
192184 bytes in 96ms
10-18 01:44:21.619: ERROR/dalvikvm-heap(872): 506844-byte external
allocation too large for this process.
10-18 01:44:21.619: ERROR/(872): VM won't let us allocate 506844 bytes
10-18 01:44:21.659: DEBUG/AndroidRuntime(872): Shutting down VM
10-18 01:44:21.659: WARN/dalvikvm(872): threadid=3: thread exiting
with uncaught exception (group=0x4001aa28)
10-18 01:44:21.659: ERROR/AndroidRuntime(872): Uncaught handler:
thread main exiting due to uncaught exception
10-18 01:44:21.709: ERROR/AndroidRuntime(872):
android.view.InflateException: Binary XML file line #47: Error
inflating class java.lang.reflect.Constructor
10-18 01:44:21.709: ERROR/AndroidRuntime(872): at
android.view.LayoutInflater.createView(LayoutInflater.java:512)
10-18 01:44:21.709: ERROR/AndroidRuntime(872): at
com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:
56)
10-18 01:44:21.709: ERROR/AndroidRuntime(872): at
android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:562)

どうしたら良いのでしょうか。(・_・?)

Ishikawa Hiromi

unread,
Oct 18, 2010, 11:18:44 PM10/18/10
to android-g...@googlegroups.com
これが出てるということはまだリークしているようです。

>10-18 01:44:21.619: ERROR/dalvikvm-heap(872): 506844-byte external
allocation too large for this process.

たぶんリークしているのはビットマップではなく、Activityのインスタンスだと思います。
以下のコードを、Activityクラスに追加してみてください。

======== ここから ========
@Override
protected void onDestroy() {
super.onDestroy();
cleanupView(findViewById(R.id.root));
// ^^^^^^^^^^
ここはアクティビティのトップレベルレイアウトのIDを指定してください。
}

/**
* 指定したビュー階層内のドローワブルをクリアする。
* (ドローワブルをのコールバックメソッドによるアクティビティのリークを防ぐため)
* @param view
*/
public static final void cleanupView(View view) {
if(view instanceof ImageButton) {
ImageButton ib = (ImageButton)view;
ib.setImageDrawable(null);
} else if(view instanceof ImageView) {
ImageView iv = (ImageView)view;
iv.setImageDrawable(null);
} else if(view instanceof SeekBar) {
SeekBar sb = (SeekBar)view;
sb.setProgressDrawable(null);
sb.setThumb(null);
// } else if(view instanceof( xxxx )) { -- 他にもDrawable
を使用するUIコンポーネントがあれば追加
}
view.setBackgroundDrawable(null);
if(view instanceof ViewGroup) {
ViewGroup vg = (ViewGroup)view;
int size = vg.getChildCount();
for(int i = 0; i < size; i++) {
cleanupView(vg.getChildAt(i));
}
}
}
======== ここまで ========

2010年10月18日13:19 Lisa <lpk...@gmail.com>:

Lisa

unread,
Oct 25, 2010, 4:33:10 AM10/25/10
to 日本Androidの会
Ishikawa Hiromi さん、ご回答有難うございました。m( _ _ )m
済みません。ちょっと風邪で今まで試す事も出来ませんでした。

でも、Ishikawaさんのコードを追加してみました。
メモリリークは成りませんでした。(〃^¬^〃)

皆様本当にアドバイス、ご協力有難うございました。┌(_ _)┐

Lisa

unread,
Oct 25, 2010, 4:52:23 AM10/25/10
to 日本Androidの会
Ishikawa Hiromi さん、本当に有難うございました。┌(_ _)┐

sinfo...@gmail.com

unread,
Feb 25, 2014, 3:22:22 AM2/25/14
to android-g...@googlegroups.com
jackと申します。

私もAndroid開発を勉強中なんで、layoutにデザイン画像を指定する場合(例:TextViewに背景指定)はどうやって画面を閉じたら、メモリを解放出来るんですか?
うちに開発したアプリはXperia系の端末で落ちやすいになっておりますが、色々調べたら、なんかいい方法を見つけないでした。
開発環境にdebugなどの手段で確認しましたが、画面を表示する際に端末側に余裕なメモリがあるのに、アプリが落ちました(outofmemory)

もし分かっている方がいますと、ぜひ教えて頂けますでしょうか。
お願いします

2010年10月8日金曜日 18時03分54秒 UTC+9 Lisa:
Reply all
Reply to author
Forward
0 new messages