Android App在运行时突然崩溃?

时间:2012-06-25 13:43:08

标签: android android-ndk

我的应用程序做了什么? 我正在开发的应用程序是一个典型的客户端服务器应用程序,使用Wifi与Windows服务器通信。应用程序有多个活动,并且确实具有大量内存和CPU要求,即本地调用speex编码/解码。

我的问题是什么? 问题是应用程序突然重启,同时工作正常。有时在突然正常工作时我会看到(在logcat中)调用Application类的构造函数(扩展API的Application类的类)。这会导致我的应用程序崩溃,因为所有全局数据都存储在Application类本身中。

我做了什么? 让我印象深刻的第一件事就是Android可能会感觉它们的内存不足,所以它会终止我的App,而不是自动重启它。所以我实现了Application类的onLowMemory()。但令我惊讶的是它从未被称为..

主要问题是什么?主要问题是Nothing is printed on LogCat。看起来即使Android本身也无法重新启动我已经运行的应用程序的原因?

这种突然重启的可能原因是什么?我怎么能避免这种情况?

我正在使用Galaxy Y,API版本是2.3.6。我的AndroidManifiest.xml看起来像

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.argusoft.roobrooAndroid"
    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>

修改 我在使用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

更新 在一步实验的同时,我故意为双数组分配了一个非常大的内存。但令我惊讶的是,没有调用 onLowMemory(),也没有重新启动应用程序而是我得到了outOfMemoryException。如果onLowMemory()永远不会被调用,为什么它在那里?

另一个问题是重启后OS已经启动了BuddyListActivity而不是LoginActivity ......真的需要帮助......

更新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 com.argusoft.roobrooAndroid.speex.SpeexEncoder.encode(Native Method)
06-29 12:07:28.406: I/dalvikvm(19308):   at com.argusoft.roobrooAndroid.speex.SpeexEncoder.encodeFrame(SpeexEncoder.java:51)
06-29 12:07:28.406: I/dalvikvm(19308):   at com.argusoft.roobrooAndroid.models.Session.capturedAudioReceived(Session.java:656)
06-29 12:07:28.406: I/dalvikvm(19308):   at com.argusoft.roobrooAndroid.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 com.argusoft.roobrooAndroid.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 com.argusoft.roobrooAndroid.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 com.argusoft.roobrooAndroid.modules.AudioPlayer.onPeriodicNotification(AudioPlayer.java:163)

解决方案 那么改变代码的测试仍然存在,到目前为止一切似乎都是正面的..问题出在JNI内部(我猜)。 @ n.Collins语句“JVM报告没有错误的事实也表明它是由您的本机代码引起的。”是解决方案最正确的指针之一。我真的感谢所有回答它的人真的以某种方式帮助了我。我实际上在尝试解决这个问题的同时删除了一组其他错误,这要归功于社区。

5 个答案:

答案 0 :(得分:18)

如果没有完整的源代码,很难确切知道发生了什么,但是Romain Guy对Google网上论坛的回答here也会有所帮助。

  当整个系统用完时,会调用

onLowMemory()   内存,而不是当你的进程内存不足时。每个应用程序   仅限于固定数量的RAM(例如Nexus One上的24 MB)。   如果你耗尽这24 MB但系统仍然有更多的RAM可用,   您将获得OutOfMemoryError但不会onLowMemory()

对于&lt;的应用程序来说,24mb的限制几乎是一成不变的。蜂窝。如果您的目标是API 11或更高版本,则可以通过声明为应用程序分配大堆来请求更多内存。文档中未提及,但在Manifest.xml中向android:largeHeap="true"标记添加application将执行此操作(尽管无法保证)。

注意:在修改后的固件(自定义ROM)上,该值可能更低或更高。我相信三星Galaxy Nexus默认是48mb,但一般来说,保持在24mb以内是一个安全的假设。索尼爱立信还有great post解释姜饼和冰淇淋三明治之间的技术差异(RAM是一个深入讨论的主题)。

祝你好运,我希望这至少可以帮助你追踪问题。

答案 1 :(得分:6)

其他海报已经涵盖了内存不足的问题。我只是添加它来调试您的本机代码,一种快速而肮脏的方法是在各个检查点添加日志消息。这是我的一个本机cpp文件的示例:

#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添加到相关*.mk文件中的LOCAL_LDLIBS变量中。然后,您可以在logcat中从本机库获取日志消息。

更新:在看到您的更新后,我认为您应该使用上述技术将日志消息记录到您的原生encode()方法中,以确切了解崩溃的位置。

答案 2 :(得分:6)

我没有足够的代表评论其他人的答案,但我认为Error 454's answer非常接近。

我的应用程序重启时没有消息,我的应用程序出现了类似的问题。我的问题是由数组溢出引起的,我试图在我的本机代码中的n+1对象数组中访问索引n。 JVM未报告错误的事实也表明它是由您的本机代码引起的。

这个问题:c++ Jni Reference Table overflow与更新2的错误日志非常相似,进一步表明您的错误在于没有匹配您的get和release调用。

如果你不明白JNI pinned reference table是什么,我想引导你注意JNI Specification sections titled "Accessing Java Objects", and the following section "Accessing Primitive Arrays"

最后,您访问原始数据数组的本机代码的一些片段将有助于解决您的问题,但与此同时,我想提请您注意对ReferenceTable overflow (max=512) JNI的答案的最终评论。其中包括:

  

GetObjectArrayElement返回带有本地引用的对象,因此您需要删除本地引用。但是只有在完成数组元素时才应该这样做。因此,您应该将DeleteLocalRef(oneDim)放在releaseIntArrayElements(oneDim)之后。

所以,请在访问数组元素时仔细检查您是否匹配了Get / Release调用,当您不再需要访问它时,删除本地参考。您可能正在访问JNI固定引用表的末尾,因为您没有删除旧对象。请记住,JNI只是Java的一个c接口,所以你必须帮助你的本机代码进行垃圾收集。

答案 3 :(得分:4)

基于更新#2,很明显您无法在JNI中取消固定数组。这意味着您使用的是Get<Type>ArrayElements,但未能将这些来电中的一个或多个与Release<Type>ArrayElements匹配。

结果,ReferenceTable溢出。寻找你打电话给Get的地方而不是叫Release。例如,您可能正在调用GetIntArrayElements,但在完成后无法调用ReleaseIntArrayElements

答案 4 :(得分:3)

可能有问题的一点是,您的应用可能会在native code内的某处崩溃,这会突然停止您的应用,而不会显示任何消息,并且Logcat中没有打印任何内容。

我有同样的问题,在尝试解码某些bitmaps时,android在native code内的某处崩溃,应用程序停止,没有显示任何消息。

关于onLowMemory() @Tom答案涵盖了它。