質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Q&A

解決済

5回答

4140閲覧

InputStreamをStringに変換しようとするとOoMが発生

sun-solar-arrow

総合スコア113

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

0グッド

0クリップ

投稿2016/06/21 09:51

編集2016/08/16 00:06

InputStreamをStringに変換しようとするとOutOfMemoryErrorが発生します。原因は何でしょうか。発生しないように出来ないでしょうか。
InputStreamはAndroidのプロジェクトのrawフォルダの中にあるバイナリファイル(5.5MB)を次のようにInputStreamに変換したものです。

Java

1 InputStream is = this.getRawResouces().openRawResouce();//thisは、ActivityのContext

メモリが876MBの環境でテストしています。
#ソースコード
##readメソッドを使って書いたコード

Java

1 static String convertInputStreamToString(InputStream is) throws IOException { 2 InputStreamReader reader = new InputStreamReader(is); 3 StringBuilder builder = new StringBuilder(); 4 char[] buf = new char[512]; 5 int numRead; 6 while (0 <= (numRead = reader.read(buf))) { 7 builder.append(buf, 0, numRead);//oom発生 8 } 9 buf=null; 10 return builder.toString(); 11 } 12//readLineは使っていません 13 static String inputStreamToString(InputStream is){ 14 BufferedReader reader = null; 15 try{ 16 reader = new BufferedReader(new InputStreamReader(is,"UTF-8")); 17 } 18 catch (UnsupportedEncodingException e){ 19 e.printStackTrace(); 20 } 21 StringBuilder sb = new StringBuilder(); 22 String b = null; 23 try{ 24 while ((b=reader.readLine()) !=null){ 25 sb.append(b); 26 } 27 } 28 catch (IOException e){ 29 30 } 31 return sb.toString(); 32 }

#呼び出し元

Java

1 private void checkVersion() throws Throwable{ 2 //呼び出し元は、onResume()のonClick() 3 InputStream versionStream=this.getResources().openRawResource(R.raw.git); 4 5 String verchecked=Event.convertInputStreamToString(versionStream); 6 //ココでreadメソッドを使って書いたコードを使って変換しようとするが、OoM発生、スローされる 7 versionStream.close();//closeは書いている 8 java.lang.Process p = null; 9 TextView vertext=(TextView) findViewById(R.id.version); 10 11 try{ 12 p=Runtime.getRuntime().exec(verchecked+" version"); 13 verchecked=null;//vercheckedはもう使わないからnull 14 InputStream returnVerison=p.getInputStream();//結果を返す 15 p=null;//pはもう使わないからnullを代入 16 String ver=Event.convertInputStreamToString(returnVerison); 17 returnVerison.close(); 18 vertext.setText(ver); 19 ver=null; 20 }catch (IOException e){ 21 e.printStackTrace(); 22 vertext.setText("取得失敗: "+e); 23 } 24 vertext=null; 25 } 26 27 protected void onResume(){ 28 super.onResume(); 29 //このクラスはMainActivity(最初に呼び出されるActivity)から呼び出される 30 Button Update=(Button) findViewById(R.id.UpdateButton); 31 Update.setOnClickListener(new OnClickListener(){ 32 @Override 33 public void onClick(View p1){ 34 try{ 35 checkVersion(); 36 }catch(OutOfMemoryError e){ 37 e.printStackTrace(); 38 Toast.makeText(GitUpdate.this,"取得失敗:"+e,Toast.LENGTH_SHORT).show(); 39 } 40 } 41 }); 42

#ヒープ
Android StudioでMemoryを見ました。
画像です。
へこんでいるところがInputStreamを変換したところです。
また、コード内でも確認しました。
MB単位です。
totalMemory(),MaxMemory()
7 ,96
#追加情報
別サイトにも前から投稿しています。別サイト:スタックオーバーフローこちらにも目を通しておいてください。
##スタックトレース

06-22 20:06:54.681 W/System.err(28046): java.lang.OutOfMemoryError 06-22 20:06:54.681 W/System.err(28046): at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:94) 06-22 20:06:54.681 W/System.err(28046): at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:145) 06-22 20:06:54.681 W/System.err(28046): at java.lang.StringBuilder.append(StringBuilder.java:216) 06-22 20:06:54.681 W/System.err(28046): at java.lang.ProcessManager.exec(ProcessManager.java:211) 06-22 20:06:54.681 W/System.err(28046): at java.lang.Runtime.exec(Runtime.java:173) 06-22 20:06:54.681 W/System.err(28046): at java.lang.Runtime.exec(Runtime.java:246) 06-22 20:06:54.681 W/System.err(28046): at java.lang.Runtime.exec(Runtime.java:189) 06-22 20:06:54.681 W/System.err(28046): at com.jimdo.solarand.git.GitUpdate.checkVersion(GitUpdate.java:153) 06-22 20:06:54.681 W/System.err(28046): at com.jimdo.solarand.git.GitUpdate.access$1000009(GitUpdate.java) 06-22 20:06:54.681 W/System.err(28046): at com.jimdo.solarand.git.GitUpdate$100000001.onClick(GitUpdate.java:50) 06-22 20:06:54.681 W/System.err(28046): at android.view.View.performClick(View.java:4487) 06-22 20:06:54.681 W/System.err(28046): at android.view.View$PerformClick.run(View.java:18746) 06-22 20:06:54.691 W/System.err(28046): at android.os.Handler.handleCallback(Handler.java:733) 06-22 20:06:54.691 W/System.err(28046): at android.os.Handler.dispatchMessage(Handler.java:95) 06-22 20:06:54.691 W/System.err(28046): at android.os.Looper.loop(Looper.java:149) 06-22 20:06:54.691 W/System.err(28046): at android.app.ActivityThread.main(ActivityThread.java:5257) 06-22 20:06:54.691 W/System.err(28046): at java.lang.reflect.Method.invokeNative(Native Method) 06-22 20:06:54.691 W/System.err(28046): at java.lang.reflect.Method.invoke(Method.java:515) 06-22 20:06:54.691 W/System.err(28046): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:788) 06-22 20:06:54.691 W/System.err(28046): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:604) 06-22 20:06:54.691 W/System.err(28046): at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132) 06-22 20:06:54.691 W/System.err(28046): at de.robv.android.xposed.XposedBridge.main(Native Method) 06-22 20:06:54.691 W/System.err(28046): at dalvik.system.NativeStart.main(Native Method)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ベストアンサー

Androidのソースコードが見当たらなかったのでJavaのソースコードを確認してみましたが、
StringBuilderクラスは、内部に保持しているバッファのサイズが足りなくなると

(元のバッファのサイズ + 1) × 2

のサイズのバッファを新たに確保しようとしています。
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/AbstractStringBuilder.java#AbstractStringBuilder.expandCapacity%28int%29

Android の実装もこれと同様であれば、条件によっては一時的に約15MB(※)のメモリを使用することになります。
※ 新しいバッファ ( = ファイルサイズ × 2) + 古いバッファ ( = ファイルサイズ)

いずれの方法にせよ、ファイルの内容全てを1度にメモリに展開しようとするとそれだけOOMの発生する確率が上がりますので、
以下のページの "java.io.Fileクラスを使用したコピー方法" を、まずは試してみてください。
http://www.openreference.org/articles/view/670

これなら、ファイルの内容を1024バイトずつ読み書きしますので、OOMが発生する確率は低いはずです。

上の方法だと実行速度が遅すぎる場合は、Apache-commons-io のFileUtils.doCopyFile メソッドの実装を参考にするなどしてみてください。
https://github.com/apache/commons-io/blob/trunk/src/main/java/org/apache/commons/io/FileUtils.java#L1114

もっとも、このコードが何をやっているのか、私には理解できませんでしたが…

投稿2016/06/23 07:41

KiyoshiMotoki

総合スコア4791

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sun-solar-arrow

2016/06/25 23:31 編集

分かりました。できないということなのでこの方法で頑張ります
guest

0

InputStreamReaderはテキストファイルを読み込むためのものです。
バイナリファイルの読み込みには不向きでしょう。

バイナリデータを無理やり文字に変換しようとしていますから、
1バイトのバイナリデータが2バイトの文字に変換される場合があり、最悪2倍のメモリを消費する結果となっているのではないかと思われます。

そもそも、バイナリファイルをどうしてStringに変換する意図がわかりません。

投稿2016/06/22 16:08

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/06/23 14:05

ともかく、バイナリデータに対してInputStreamReaderで読み込むことはできません。
sun-solar-arrow

2016/06/25 23:31 編集

分かりました。バイナリデータを読み込まず別の方法でします。
guest

0

OutOfMemoryErrorはtoStringで発生しているわけではなく、appendで発生しているようですよ?
ファイルのデータを文字列に変換しようとしたものの、文字列として扱うにはデータ量が多すぎるのではないですか?ましてやAndroidなので、メモリの制約も厳しいはずです。

投稿2016/06/22 16:19

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sun-solar-arrow

2016/06/23 06:47

分かりました。appendで発生していると書き直します。
eripong

2016/06/23 07:45

というかそもそも、 Runtime.getRuntime().exec(verchecked+" version"); した行でOOMEになっているみたいで、InputStreamからの読み込みではない様です。
guest

0

なにかほかに非同期で処理をしていたりしませんか?

エラーログの追加をお願いします。

投稿2016/06/21 12:42

yona

総合スコア18155

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yona

2016/06/22 11:59

ファイルの中にある文字数はわかりますか?
sun-solar-arrow

2016/06/22 12:54

質問の通りバイナリファイルなんで…ファイルサイズは5.5MBです。 文字数をプログラム作って調べようとするとOoMも発生しますから分かりませんね。
guest

0

return builder.toString(); ではなくて、
return new String(sb) を使ってみてください。

投稿2016/06/21 10:24

maiko0318

総合スコア876

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問