我的应用程序是做什么的?我正在开发的应用程序是一个典型的客户端服务器应用程序,它使用Wifi与Windows服务器通信。该应用程序具有多个活动,并且确实具有繁重的内存和CPU要求,即对speex编码/解码的本机调用。
我的问题是什么?问题是应用程序在工作正常时突然重新启动。有时在正常工作时,我突然看到(在logcat中)应用程序类的构造函数(扩展API的应用程序类的类)被调用。这会使我的应用程序崩溃,因为所有全局数据都存储在应用程序类本身中。
我做了什么?让我印象深刻的第一件事是,可能是Android觉得内存不足,所以它会终止我的应用程序,然后自动重新启动它。所以我实现了应用程序类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="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>
编辑我刚刚在使用 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()既没有调用也没有重新启动应用程序,而是我得到了OfMemoryException。如果 onLowMemory() 从未被调用,为什么它在那里?
另一个问题是,重新启动操作系统后已经启动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 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 没有报告错误这一事实也表明它是由您的本机代码引起的。是解决方案最正确的指针之一。我真的感谢所有回答这个问题的人,他们真的以某种方式帮助了我。我实际上删除了一组其他错误,同时试图解决这个问题,这一切都归功于社区。
如果没有完整的源代码,很难确切地说出发生了什么,但也许Romain Guy在Google Groups上的回答会有所帮助。
当整个系统用完时调用
onLowMemory()
内存,而不是在进程内存不足时。每个应用程序都是 限制为固定数量的RAM(例如,在Nexus One上为24 MB)。 如果您用完了这 24 MB,但系统仍有更多可用 RAM, 你会得到一个OutOfMemoryError
,但不会得到onLowMemory()
。
24mb 的限制对于
注意:在修改后的固件(自定义ROM)上,该值可能会更低或更高。我相信在三星Galaxy Nexus上,默认情况下它是48mb,但作为一般规则,保持在24mb以内是一个安全的假设。索尼爱立信上也有一篇很棒的帖子,解释了姜饼和冰淇淋三明治之间的技术差异(RAM是一个深入探讨的主题)。
祝你好运,我希望这至少可以帮助您追踪问题。
其他海报已经涵盖了内存不足的问题。 我只是添加它来调试您的本机代码,一种快速而肮脏的方法是在各个检查点添加日志消息。 这是我的一个本机 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()
方法中,以准确查看崩溃的位置。
我没有足够的代表来评论其他人的答案,但我认为错误 454 的答案非常接近。
我自己的应用程序遇到了类似的问题,应用程序重新启动时没有消息。我的问题是由数组溢出引起的,我尝试访问本机代码中n
对象数组中的索引n+1
。JVM 未报告任何错误这一事实也表明它是由本机代码引起的。
这个问题:c++ Jni 参考表溢出的错误日志与更新 2 非常相似,进一步表明您的错误在于与您的获取和释放调用不匹配。
如果您不了解JNI pinned reference table
是什么,我想提请您注意标题为"访问 Java 对象"的 JNI 规范部分,以及以下部分"访问基元数组"。
最后,访问原始数据数组的本机代码的一些片段将有助于解决您的问题,但与此同时,我想提请您注意对 ReferenceTable 溢出(max=512)JNI 答案的最后评论,内容如下:
GetObjectArrayElement
返回带有本地引用的对象,因此您需要删除本地引用。但是,只有在完成数组元素后,才应执行此操作。所以你应该把DeleteLocalRef(oneDim)
放在releaseIntArrayElements(oneDim)
之后.
因此,请在访问数组元素时仔细检查您是否匹配了 Get/Release 调用,当您不再需要访问它时,请删除本地引用。您可能正在点击 JNI 固定引用表的末尾,因为您没有删除旧对象。请记住,JNI 只是 Java 的一个 c 接口,因此您必须帮助原生代码进行垃圾回收。
基于更新 #2,很明显您未能在 JNI 中取消固定数组。 这意味着您正在使用Get<Type>ArrayElements
,并且未能将这些呼叫中的一个或多个与Release<Type>ArrayElements
匹配。
因此,引用表溢出。 查找您调用 Get 而不调用 Release 的位置。 例如,您可能正在呼叫GetIntArrayElements
但在完成后无法调用ReleaseIntArrayElements
。
可能是问题的一件事是,也许您的应用程序在native code
内的某个地方崩溃,这将突然停止您的应用程序,没有任何消息,并且Logcat
中没有打印任何内容。
我遇到了同样的问题,在尝试解码一些bitmaps
时,android 在native code
内部的某个地方崩溃,应用程序停止,没有显示任何消息。
关于onLowMemory()
@Tom答案涵盖了它。