30

私のアプリは何をしますか? 私が開発しているアプリは、Wifi を使用して Windows サーバーと通信する典型的なクライアント サーバー アプリです。アプリケーションには複数のアクティビティがあり、メモリと CPU の要件が非常に高くなります。つまり、speex エンコード/デコードのネイティブ呼び出しです。

私の問題は何ですか? 問題は、アプリケーションが完全に正常に動作しているときに突然再起動することです。正常に動作しているときに、( logcat で) アプリケーション クラス (API のアプリケーション クラスを拡張するクラス) のコンストラクタが呼び出されていることが時々わかります。すべてのグローバルデータが Application クラス自体に保存されているため、これによりアプリがクラッシュします。

私がやった事 ? 私の頭に浮かんだ最初のことは、Android がメモリ不足を感じてアプリを終了し、自動的に再起動する可能性があるということでした。だから私onLowMemory()は Application クラスを実装しました。しかし、驚いたことに、それは決して呼び出されません..

主な問題は何ですか? 主な問題は、Nothing is printed on LogCat. Android 自体でさえ、既に実行中の Application を再起動した理由について無知であるように見えますか?

この突然の再起動の考えられる理由は何ですか? どうすればそれを回避できますか?

私は Galaxy Y で作業しており、API バージョンは 2.3.6 です。私の AndroidManifest.xml は次のようになります

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="some.package.MyApp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:maxSdkVersion="15"
        android:minSdkVersion="10"
        android:targetSdkVersion="10" />

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_VIDEO" />

    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />

    <application
        android:name="some.package.MyApp"
        android:icon="@drawable/display_image"
        android:label="@string/app_name" >
        <activity
            android:name="some.package.LoginActivity"
            android:configChanges="keyboardHidden|orientation"
            android:label="@string/app_name"
            android:screenOrientation="user" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="some.package.BuddyListActivity"
            android:configChanges="keyboardHidden|orientation"
            android:label="@string/app_name"
            android:screenOrientation="user"
            android:theme="@android:style/Theme.Black.NoTitleBar" >

            <!--
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            -->
        </activity>
        <activity
            android:name="some.package.SessionWindowActivity"
            android:configChanges="keyboardHidden|orientation"
            android:label="@string/app_name"
            android:screenOrientation="user"
            android:theme="@android:style/Theme.Black.NoTitleBar" >

            <!--
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            -->
        </activity>
    </application>

</manifest>

EDIT CheckJNIを使​​用した後、LogCatで次の出力を見ました。

06-26 17:27:30.023: I/remove(24544): Sending Signal : 13 **//App Working fine here**
06-26 17:27:32.148: D/dalvikvm(24544): GC_CONCURRENT freed 446K, 49% free 3384K/6599K, external 1057K/1076K, paused 3ms+4ms
06-26 17:27:39.531: W/dalvikvm(24544): **HeapWorker may be wedged: 7374ms spent** inside LsomePackageName/modules/AudioPlayer;.finalize()V
06-26 17:27:40.023: I/remove(24544): Sending Signal : 13
06-26 17:27:40.218: D/dalvikvm(24544): GC_CONCURRENT freed 479K, 49% free 3383K/6599K, external 1057K/1076K, paused 9ms+5ms 
06-26 17:27:42.343: E/RoobrooApp(24670): Application Instance created **//Restarted** 
06-26 17:27:42.351: I/ApplicationPackageManager(24670): cscCountry is not German : INS

更新 1 つのステップでさらに実験を行っているときに、double 配列に非常に大きなメモリを意図的に割り当てました。しかし、驚いたことに、onLowMemory()が呼び出されず、アプリが再起動されず、outOfMemoryException が発生しました。onLowMemory() が呼び出されない場合、なぜそこにあるのですか?

もう1つの問題は、OSを再起動した後、LoginActivityではなくBuddyListActivityがすでに開始されていることです...本当に助けが必要です....

更新 2 次のエラー ログを見たところ、それが何を意味するのか本当にわかりません..

06-29 12:07:28.398: W/dalvikvm(19308): ReferenceTable overflow (max=1024)
06-29 12:07:28.398: W/dalvikvm(19308): Last 10 entries in JNI pinned array reference table:
06-29 12:07:28.398: W/dalvikvm(19308):  1014: 0x405b0280 cls=[B (340 bytes)
06-29 12:07:28.398: W/dalvikvm(19308):  1015: 0x405b03d8 cls=[S (660 bytes)
06-29 12:07:28.398: W/dalvikvm(19308):  1016: 0x405d8208 cls=[B (340 bytes)
06-29 12:07:28.398: W/dalvikvm(19308):  1017: 0x405d8360 cls=[S (660 bytes)
06-29 12:07:28.398: W/dalvikvm(19308):  1018: 0x405f8b08 cls=[B (340 bytes)
06-29 12:07:28.398: W/dalvikvm(19308):  1019: 0x405f8c60 cls=[S (660 bytes)
06-29 12:07:28.398: W/dalvikvm(19308):  1020: 0x405f8ef8 cls=[B (340 bytes)
06-29 12:07:28.398: W/dalvikvm(19308):  1021: 0x405ff698 cls=[S (660 bytes)
06-29 12:07:28.398: W/dalvikvm(19308):  1022: 0x405f9050 cls=[B (340 bytes)
06-29 12:07:28.398: W/dalvikvm(19308):  1023: 0x405ff930 cls=[S (660 bytes)
06-29 12:07:28.398: W/dalvikvm(19308): JNI pinned array reference table summary (1024 entries):
06-29 12:07:28.398: W/dalvikvm(19308):     1 of [B 20B
06-29 12:07:28.398: W/dalvikvm(19308):   508 of [B 340B (508 unique)
06-29 12:07:28.398: W/dalvikvm(19308):     3 of [B 348B (3 unique)
06-29 12:07:28.406: W/dalvikvm(19308):   511 of [S 660B (511 unique)
06-29 12:07:28.406: W/dalvikvm(19308):     1 of [S 668B
06-29 12:07:28.406: W/dalvikvm(19308): Memory held directly by tracked refs is 511712 bytes
06-29 12:07:28.406: E/dalvikvm(19308): Failed adding to JNI pinned array ref table (1024 entries)
06-29 12:07:28.406: I/dalvikvm(19308): "Thread-14" prio=5 tid=12 RUNNABLE
06-29 12:07:28.406: I/dalvikvm(19308):   | group="main" sCount=0 dsCount=0 obj=0x4050e548 self=0x2240b8
06-29 12:07:28.406: I/dalvikvm(19308):   | sysTid=19953 nice=-19 sched=0/0 cgrp=[fopen-error:2] handle=1905240
06-29 12:07:28.406: I/dalvikvm(19308):   | schedstat=( 207153329 82244881 1015 )
06-29 12:07:28.406: I/dalvikvm(19308):   at some.package.MyApp.speex.SpeexEncoder.encode(Native Method)
06-29 12:07:28.406: I/dalvikvm(19308):   at some.package.MyApp.speex.SpeexEncoder.encodeFrame(SpeexEncoder.java:51)
06-29 12:07:28.406: I/dalvikvm(19308):   at some.package.MyApp.models.Session.capturedAudioReceived(Session.java:656)
06-29 12:07:28.406: I/dalvikvm(19308):   at some.package.MyApp.modules.AudioCapturer.run(AudioCapturer.java:118)
06-29 12:07:28.406: I/dalvikvm(19308):   at java.lang.Thread.run(Thread.java:1019)
06-29 12:07:28.406: E/dalvikvm(19308): VM aborting
06-29 12:07:29.726: W/AudioTrack(19308): obtainBuffer() track 0x1d3520 disabled, restarting
06-29 12:07:30.351: W/dalvikvm(19308): threadid=4: spin on suspend #1 threadid=1 (pcf=0)
06-29 12:07:30.898: W/AudioTrack(19308): obtainBuffer() track 0x1d3520 disabled, restarting
06-29 12:07:31.101: W/dalvikvm(19308): threadid=4: spin on suspend #2 threadid=1 (pcf=0)
06-29 12:07:31.101: I/dalvikvm(19308): "Signal Catcher" daemon prio=5 tid=4 RUNNABLE
06-29 12:07:31.101: I/dalvikvm(19308):   | group="system" sCount=0 dsCount=0 obj=0x40510490 self=0x159898
06-29 12:07:31.101: I/dalvikvm(19308):   | sysTid=19312 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=1575600
06-29 12:07:31.101: I/dalvikvm(19308):   | schedstat=( 1556395 4913328 26 )
06-29 12:07:31.101: I/dalvikvm(19308):   at dalvik.system.NativeStart.run(Native Method)
06-29 12:07:31.101: I/dalvikvm(19308): "main" prio=5 tid=1 RUNNABLE
06-29 12:07:31.101: I/dalvikvm(19308):   | group="main" sCount=1 dsCount=0 obj=0x40022198 self=0xcec8
06-29 12:07:31.101: I/dalvikvm(19308):   | sysTid=19308 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-1345006496
06-29 12:07:31.101: I/dalvikvm(19308):   | schedstat=( 5364166234 3306213349 13647 )
06-29 12:07:31.101: I/dalvikvm(19308):   at android.media.AudioTrack.native_write_short(Native Method)
06-29 12:07:31.101: I/dalvikvm(19308):   at android.media.AudioTrack.write(AudioTrack.java:943)
06-29 12:07:31.101: I/dalvikvm(19308):   at some.package.MyApp.modules.AudioPlayer.onPeriodicNotification(AudioPlayer.java:163)
06-29 12:07:31.101: I/dalvikvm(19308):   at android.media.AudioTrack$NativeEventHandlerDelegate$1.handleMessage(AudioTrack.java:1084)
06-29 12:07:31.101: I/dalvikvm(19308):   at android.os.Handler.dispatchMessage(Handler.java:99)
06-29 12:07:31.101: I/dalvikvm(19308):   at android.os.Looper.loop(Looper.java:130)
06-29 12:07:31.101: I/dalvikvm(19308):   at android.app.ActivityThread.main(ActivityThread.java:3687)
06-29 12:07:31.101: I/dalvikvm(19308):   at java.lang.reflect.Method.invokeNative(Native Method)
06-29 12:07:31.101: I/dalvikvm(19308):   at java.lang.reflect.Method.invoke(Method.java:507)
06-29 12:07:31.101: I/dalvikvm(19308):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
06-29 12:07:31.101: I/dalvikvm(19308):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
06-29 12:07:31.101: I/dalvikvm(19308):   at dalvik.system.NativeStart.main(Native Method)
06-29 12:07:31.851: W/dalvikvm(19308): threadid=4: spin on suspend #3 threadid=1 (pcf=0)
06-29 12:07:31.851: I/dalvikvm(19308): "Signal Catcher" daemon prio=5 tid=4 RUNNABLE
06-29 12:07:31.851: I/dalvikvm(19308):   | group="system" sCount=0 dsCount=0 obj=0x40510490 self=0x159898
06-29 12:07:31.851: I/dalvikvm(19308):   | sysTid=19312 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=1575600
06-29 12:07:31.851: I/dalvikvm(19308):   | schedstat=( 2868652 6927485 37 )
06-29 12:07:31.851: I/dalvikvm(19308):   at dalvik.system.NativeStart.run(Native Method)
06-29 12:07:31.851: I/dalvikvm(19308): "main" prio=5 tid=1 RUNNABLE
06-29 12:07:31.851: I/dalvikvm(19308):   | group="main" sCount=1 dsCount=0 obj=0x40022198 self=0xcec8
06-29 12:07:31.851: I/dalvikvm(19308):   | sysTid=19308 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-1345006496
06-29 12:07:31.851: I/dalvikvm(19308):   | schedstat=( 5364166234 3306213349 13647 )
06-29 12:07:32.000: I/dalvikvm(19308):   at android.media.AudioTrack.native_write_short(Native Method)
06-29 12:07:32.015: I/dalvikvm(19308):   at android.media.AudioTrack.write(AudioTrack.java:943)
06-29 12:07:32.031: I/dalvikvm(19308):   at some.package.MyApp.modules.AudioPlayer.onPeriodicNotification(AudioPlayer.java:163)
06-29 12:07:32.039: I/dalvikvm(19308):   at android.media.AudioTrack$NativeEventHandlerDelegate$1.handleMessage(AudioTrack.java:1084)
06-29 12:07:32.054: I/dalvikvm(19308):   at android.os.Handler.dispatchMessage(Handler.java:99)
06-29 12:07:32.054: I/dalvikvm(19308):   at android.os.Looper.loop(Looper.java:130)
06-29 12:07:32.062: W/AudioTrack(19308): obtainBuffer() track 0x1d3520 disabled, restarting
06-29 12:07:32.070: I/dalvikvm(19308):   at android.app.ActivityThread.main(ActivityThread.java:3687)
06-29 12:07:32.093: I/dalvikvm(19308):   at java.lang.reflect.Method.invokeNative(Native Method)
06-29 12:07:32.101: I/dalvikvm(19308):   at java.lang.reflect.Method.invoke(Method.java:507)
06-29 12:07:32.109: I/dalvikvm(19308):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
06-29 12:07:32.125: I/dalvikvm(19308):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
06-29 12:07:32.132: I/dalvikvm(19308):   at dalvik.system.NativeStart.main(Native Method)
06-29 12:07:32.890: W/dalvikvm(19308): threadid=4: spin on suspend #4 threadid=1 (pcf=0)
06-29 12:07:32.890: I/dalvikvm(19308): "Signal Catcher" daemon prio=5 tid=4 RUNNABLE
06-29 12:07:32.890: I/dalvikvm(19308):   | group="system" sCount=0 dsCount=0 obj=0x40510490 self=0x159898
06-29 12:07:32.890: I/dalvikvm(19308):   | sysTid=19312 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=1575600
06-29 12:07:32.890: I/dalvikvm(19308):   | schedstat=( 5340582 316192616 59 )
06-29 12:07:32.898: I/dalvikvm(19308):   at dalvik.system.NativeStart.run(Native Method)
06-29 12:07:32.898: I/dalvikvm(19308): "main" prio=5 tid=1 RUNNABLE
06-29 12:07:32.898: I/dalvikvm(19308):   | group="main" sCount=1 dsCount=0 obj=0x40022198 self=0xcec8
06-29 12:07:32.898: I/dalvikvm(19308):   | sysTid=19308 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-1345006496
06-29 12:07:32.898: I/dalvikvm(19308):   | schedstat=( 5364166234 3306213349 13647 )
06-29 12:07:32.929: I/dalvikvm(19308):   at android.media.AudioTrack.native_write_short(Native Method)
06-29 12:07:32.945: I/dalvikvm(19308):   at android.media.AudioTrack.write(AudioTrack.java:943)
06-29 12:07:32.953: I/dalvikvm(19308):   at some.package.MyApp.modules.AudioPlayer.onPeriodicNotification(AudioPlayer.java:163)

ソリューション さて、変更されたコードのテストはまだ行われており、これまでのところすべてが順調に進んでいるようです。問題は JNI の内部にありました (推測します)。@n.Collins ステートメント「JVM によってエラーが報告されないという事実は、ネイティブ コードが原因であることも示しています。」ソリューションへの最も正しい指針の 1 つでした。回答してくれたすべての人に本当に感謝しています。何らかの形で私を助けてくれました。コミュニティのおかげで、この問題を解決しようとしているときに、実際に他の一連のバグを削除しました。

4

5 に答える 5

19

完全なソース コードなしで何が起こっているのかを正確に伝えることは困難ですが、おそらく Google グループに関する Romain Guy の回答役立つでしょう。

onLowMemory()プロセスがメモリ不足になったときではなく、システム全体がメモリ不足になったときに呼び出されます。各アプリは一定量の RAM に制限されています (たとえば、Nexus One では 24 MB)。これらの 24 MB を使い果たしたが、システムにまだ使用可能な RAM がある場合、 は取得されますが、 は取得されOutOfMemoryErrorませんonLowMemory()

< Honeycomb 上のアプリケーションでは、24MB の制限はほぼ確定されています。API 11 以降をターゲットにしている場合は、アプリケーションに大きなヒープを割り当てることを宣言することで、より多くのメモリを要求できます。ドキュメントには記載されていませんが、Manifest.xml のタグに追加android:largeHeap="true"すると、applicationこれが行われます (ただし、保証はされません)。

注: 変更されたファームウェア (カスタム ROM) では、その値が低くなったり高くなったりする可能性があります。Samsung Galaxy Nexus ではデフォルトで 48 MB だと思いますが、一般的には 24 MB 以内に収まるのが安全な想定です。また、Sony Ericsson には、Gingerbread と Ice Cream Sandwich の技術的な違いを説明している素晴らしい投稿があります (RAM は詳細に説明されているトピックです)。

頑張ってください、これが少なくとも問題を追跡するのに役立つことを願っています.

于 2012-06-27T14:33:24.983 に答える
6

他のポスターは、メモリ不足の問題をカバーしています。ネイティブ コードをデバッグするためにそれを追加するだけです。手っ取り早い方法の 1 つは、さまざまなチェックポイントにログ メッセージを追加することです。これは、私のネイティブ cpp ファイルの 1 つからの例です。

#include <android/log.h>

...

// Set to 1 to enable debug log traces...
#define DEBUG  0

#define LOG_TAG         "yourNativeCodeLogTag"
#if DEBUG
#define LOG_ERROR(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define LOG_WARN(...)   __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOG_INFO(...)   __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOG_DEBUG(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#else // if !DEBUG
#define LOG_ERROR(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define LOG_WARN(...)   __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOG_INFO(...)   
#define LOG_DEBUG(...) 
#endif // DEBUG

...

extern "C"
JNIEXPORT void JNICALL Java_com_whatever_package_YourClassName_jniInitializeLibrary(JNIEnv * env, jobject thiz, /* other irrelevant stuff here */)                 
{    
    LOG_DEBUG("Initializing native library.\n");
    ....
}

最後に、関連ファイル-llogの LOCAL_LDLIBS 変数にも追加する必要があります。*.mk次に、logcat でネイティブ ライブラリからログ メッセージを取得できます。

encode()更新:更新を確認した後、上記の手法を使用してログ メッセージをネイティブメソッドに追加し、クラッシュした場所を正確に確認する必要があると思います。

于 2012-06-30T02:57:46.263 に答える
6

他の人の回答にコメントするのに十分な担当者がいませんが、エラー 454 の回答はかなり近いと思います。

メッセージなしでアプリケーションを再起動するという、自分のアプリでも同様の問題がありました。私の問題は、ネイティブ コードでオブジェクトn+1の配列のインデックスにアクセスしようとしたときに、配列のオーバーフローが原因でした。nJVM によってエラーが報告されないという事実は、ネイティブ コードが原因であることも示しています。

この質問: c++ Jni 参照テーブル オーバーフローには、更新 2 と非常によく似たエラー ログがあり、get 呼び出しと release 呼び出しが一致していないことにエラーがあることをさらに示しています。

が何であるかを理解していない場合は、 「Java オブジェクトへのアクセス」というタイトルの JNI 仕様セクションと、次の「プリミティブ配列へのアクセス」セクションJNI pinned reference tableに注意を向けてください。

最後に、プリミティブ データ配列にアクセスするネイティブ コードのスニペットは、問題の解決に役立ちますが、それまでの間、ReferenceTable オーバーフロー (最大 = 512) JNIへの回答に関する最後のコメントに注意を向けたいと思います。これは次のとおりです。

GetObjectArrayElementローカル参照を持つオブジェクトを返すため、ローカル参照を削除する必要があります。ただし、これは配列要素の処理が完了したときにのみ行う必要があります。DeleteLocalRef(oneDim)したがって、 の後に置く必要がありますreleaseIntArrayElements(oneDim)

そのため、配列要素にアクセスするときにGet/Release 呼び出しが一致していることを再確認し、アクセスする必要がなくなったらローカル参照を削除してください。古いオブジェクトを削除していないため、JNI 固定参照テーブルの終わりに到達している可能性があります。JNI は単なる Java の ac インターフェースであるため、ネイティブ コードのガベージ コレクションを支援する必要があることを忘れないでください。

于 2012-07-04T13:02:43.000 に答える
4

Update #2 に基づくと、JNI で配列の固定解除に失敗したことは明らかです。これは、 を使用してGet<Type>ArrayElementsいて、これらの呼び出しの 1 つ以上を と一致させることができなかったことを意味しますRelease<Type>ArrayElements

その結果、ReferenceTable がオーバーフローします。Get を呼び出して Release を呼び出していない場所を探します。たとえば、電話をかけているが、終わったときGetIntArrayElementsに電話をかけられないことがあります。ReleaseIntArrayElements

于 2012-07-02T05:57:57.483 に答える
3

問題になる可能性のあることの 1 つは、アプリが 内のどこかでクラッシュしnative code、メッセージが表示されずにアプリが突然停止し、 に何も出力されないことLogcatです。

私は同じ問題を抱えていました.いくつかをデコードしようとしているbitmapsときに、Androidが内部のどこかでクラッシュしnative code、アプリが停止しました.

onLowMemory()@Tomの回答については、それをカバーしています。

于 2012-06-28T10:30:46.133 に答える