为什么 PhoneGap Android 应用程序在将大量数据插入 SQL 时崩溃?
我有在 Android 中运行的 PhoneGap 应用程序。当应用程序启动时,它会在 SQL 中插入大约 500 行。表有 10 列。这不是很多数据,我在文本文件中有一个 JSON,它的大小约为 120 kB。我认为这根本无法触及任何限制,但可能存在一些我不知道的限制,或者可能是 Android 中的错误,因为同一个应用程序在某些版本的 Android (2.2) 上运行没有问题,但立即崩溃或者在其他版本的 Android(1.6、2.1、一些 2.3 可能更多...)上使用 SQL 数据库时需要几分钟。
这是我用来填充在 Android 1.6 上崩溃的数据库的代码:
db = window.openDatabase("db", "1.0", "Description", 1000000);
$.get('db/app_data.dat',function(result){
var data = $.parseJSON(result);
try {
db.transaction(function(tx){
$.each(data.items, function(i, v){
try {
tx.executeSql('INSERT INTO table(c1,c2,c3, ...) VALUES (?,?,?, ...)',[v.c1, v.c2, v.c3, ...]);
} catch(e) {
alert(e.message);
}
});
});
} catch(e) {
alert(e.message);
return;
}
});
有人可以帮助我吗?有什么我不知道的限制吗?或者我在 SQL 数据库中插入数据时做错了什么?
编辑:
这是 LogCat 的输出,我认为这些是应用程序崩溃时日志中的一些重要行。然而,我对Java和Android没有更深入的了解:
WARN/dalvikvm(1525): ReferenceTable overflow (max=512)
WARN/dalvikvm(1525): Last 10 entries in JNI local reference table:
WARN/dalvikvm(1525): 502: 0x4375cbb8 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 503: 0x4374c9a0 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 504: 0x4377c5c0 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 505: 0x437c3040 cls=Ljava/lang/String; (36 bytes)
WARN/dalvikvm(1525): 506: 0x43760bd8 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 507: 0x437625e8 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 508: 0x43762608 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 509: 0x43762628 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 510: 0x43759178 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 511: 0x43766808 cls=Landroid/webkit/WebViewCore; (116 bytes)
ERROR/dalvikvm(1525): Failed adding to JNI local ref table (has 512 entries)
INFO/dalvikvm(1525): "WebViewCoreThread" prio=5 tid=15 RUNNABLE
INFO/dalvikvm(1525): | group="main" sCount=0 dsCount=0 s=N obj=0x437668a0 self=0x1b0bd0
INFO/dalvikvm(1525): | sysTid=1532 nice=0 sched=0/0 handle=1772784
INFO/dalvikvm(1525): at android.webkit.LoadListener.nativeFinished(Native Method)
INFO/dalvikvm(1525): at android.webkit.LoadListener.tearDown(LoadListener.java:1076)
INFO/dalvikvm(1525): at android.webkit.LoadListener.handleEndData(LoadListener.java:642)
INFO/dalvikvm(1525): at android.webkit.LoadListener.handleMessage(LoadListener.java:203)
INFO/dalvikvm(1525): at android.os.Handler.dispatchMessage(Handler.java:99)
INFO/dalvikvm(1525): at android.os.Looper.loop(Looper.java:123)
INFO/dalvikvm(1525): at android.webkit.WebViewCore$WebCoreThread.run(WebViewCore.java:471)
INFO/dalvikvm(1525): at java.lang.Thread.run(Thread.java:1060)
ERROR/dalvikvm(1525): VM aborting
DEBUG/Zygote(30): Process 1525 terminated by signal (11)
I have PhoneGap app running in Android. When the app starts, it inserts approximately 500 rows into SQL. Table has 10 columns. It's not a lot of data, I have a JSON in textfile and its size is about 120 kB. I thought this couldn't touch any limits at all, but there is probably some limitation I don't know about or maybe a bug in Android, because this same app runs on some versions of Android (2.2) without problem, but crashes immediately or in few minutes when working with the SQL database on other versions of Android (1.6, 2.1, some 2.3 probably more...)
Here is the code I use to populate the DB that crashes on Android 1.6:
db = window.openDatabase("db", "1.0", "Description", 1000000);
$.get('db/app_data.dat',function(result){
var data = $.parseJSON(result);
try {
db.transaction(function(tx){
$.each(data.items, function(i, v){
try {
tx.executeSql('INSERT INTO table(c1,c2,c3, ...) VALUES (?,?,?, ...)',[v.c1, v.c2, v.c3, ...]);
} catch(e) {
alert(e.message);
}
});
});
} catch(e) {
alert(e.message);
return;
}
});
Can anybody help me ? Is there some limit I don't know about ? Or am I doing something wrong when inserting data in the SQL database ?
EDIT:
Here is output of LogCat, I think these are some important lines from log when app crashes. However, I have no deeper knowledge of Java and Android:
WARN/dalvikvm(1525): ReferenceTable overflow (max=512)
WARN/dalvikvm(1525): Last 10 entries in JNI local reference table:
WARN/dalvikvm(1525): 502: 0x4375cbb8 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 503: 0x4374c9a0 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 504: 0x4377c5c0 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 505: 0x437c3040 cls=Ljava/lang/String; (36 bytes)
WARN/dalvikvm(1525): 506: 0x43760bd8 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 507: 0x437625e8 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 508: 0x43762608 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 509: 0x43762628 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 510: 0x43759178 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525): 511: 0x43766808 cls=Landroid/webkit/WebViewCore; (116 bytes)
ERROR/dalvikvm(1525): Failed adding to JNI local ref table (has 512 entries)
INFO/dalvikvm(1525): "WebViewCoreThread" prio=5 tid=15 RUNNABLE
INFO/dalvikvm(1525): | group="main" sCount=0 dsCount=0 s=N obj=0x437668a0 self=0x1b0bd0
INFO/dalvikvm(1525): | sysTid=1532 nice=0 sched=0/0 handle=1772784
INFO/dalvikvm(1525): at android.webkit.LoadListener.nativeFinished(Native Method)
INFO/dalvikvm(1525): at android.webkit.LoadListener.tearDown(LoadListener.java:1076)
INFO/dalvikvm(1525): at android.webkit.LoadListener.handleEndData(LoadListener.java:642)
INFO/dalvikvm(1525): at android.webkit.LoadListener.handleMessage(LoadListener.java:203)
INFO/dalvikvm(1525): at android.os.Handler.dispatchMessage(Handler.java:99)
INFO/dalvikvm(1525): at android.os.Looper.loop(Looper.java:123)
INFO/dalvikvm(1525): at android.webkit.WebViewCore$WebCoreThread.run(WebViewCore.java:471)
INFO/dalvikvm(1525): at java.lang.Thread.run(Thread.java:1060)
ERROR/dalvikvm(1525): VM aborting
DEBUG/Zygote(30): Process 1525 terminated by signal (11)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Phobos 的答案有一些相关信息,但不包括它如何应用于您的问题或如何解决您的特定问题。我在 android javascript 中进行一些性能测试时遇到了类似的问题,该测试通过使用 addJavascriptInterface 绑定到 webview 上下文中的对象来调用 java。虽然我没有明确使用 JNI,但显然在幕后,绑定接口使用 JNI 来编组数据 - 我收到了与您类似的错误和堆栈跟踪。显然,webDB 或 localStorage 或您在那里所做的任何事情也在幕后使用 JNI。
根据 Phobos 链接的信息,当您使用 JNI 时,您可以在范围内拥有的引用数量是有限的。对于间接使用 JNI 的 javascript,似乎必须根据 javascript 范围保留引用。看看你的代码,我不确定你到底做了什么来超出限制,但看起来可能是你在整个交易中进行的调用次数,或者你的值数组最终有超过 512 个元素。如果您需要保持事务完整性并且您确实有超过 500 次操作,那么您可能就不那么幸运了。不过,我怀疑您应该能够找到一种方法来避免 512 限制,方法是重写代码以在 tx.executeSql 调用范围之外构建查询字符串。
也许您可以重写代码来构建查询字符串,然后在匿名函数包装器中实际调用 tx.executeSql ?您可能需要构建包含值的字符串,而不是使用
'INSERT INTO table() VALUES()',[]
语法...正如我上面所说,如果您有超过 500 个操作交易时,您可能仍会遇到麻烦,但值得一试!PS 作为参考,这里是我的代码的一个版本,它随着修复而崩溃:
test() 崩溃并出现如下错误:
03-28 10:57:45.634: W/dalvikvm(21294): ReferenceTable Overflow ( max=512)
test2() 不会崩溃。
Phobos' answer has some pertinent information, but it doesn't include how it applies to your problem or how to fix your specific problem. I ran into a similar issue while doing some performance testing in android javascript that calls across to java via an object bound into the webview context with addJavascriptInterface. Although I am not explicitly using JNI, apparently under the covers the bound interface uses JNI to marshall the data across - I was getting an error and stack trace similar to yours. Apparently, webDB or localStorage or whatever you are doing there also uses JNI under the covers.
As per the info that Phobos linked, there is a finite limit to the number of references you can have in scope when you are using JNI. In the case of javascript that indirectly uses JNI, it seems that the references must be kept around based on the javascript scope. Looking at your code, I'm not sure exactly what you are doing to exceed the limit, but it looks like it could be either the number of calls you make in the transaction overall or your values arrays end up having more than 512 elements. If you need to preserve transactional integrity and you really have over 500 operations you might be out of luck. However I suspect that you should be able to find a way to avoid the 512 limit by rewriting your code to build up a query string outside of the scope of the
tx.executeSql
call.Maybe you could rewrite the code to build your query strings and then actually call
tx.executeSql
inside an anonymous function wrapper? You probably need to build strings containing the values instead of using the'INSERT INTO table() VALUES()',[]
syntax... As I said above, if you have more than 500 operations in a transaction, you might still run into trouble, but it would be worth a try!P.S. For reference, here is a version of my code that was crashing along with the fix:
test() crashes with an error like:
03-28 10:57:45.634: W/dalvikvm(21294): ReferenceTable overflow (max=512)
test2() doesn't crash.
也许您需要像这样的递归回调函数:
Maybe you need a recursive callback function like this:
好的。找到了答案。本地引用的限制为 512 个。您需要做的是使用 NewGlobalRef() 将它们转换为全局引用,或者立即清理局部变量
如果不需要它们,则在创建它们之后。然而,将它们更改为全局引用会泄漏内存。
请查看此帖子,了解有关此已知问题的详细信息。
OK. Found the answer. It's a limit of 512 local references. What you need to do is convert them to global references using NewGlobalRef(), or to clean up the locals shortly
after creating them if they're not needed. Changing them to global references will leak memory however.
Check out this thread for more information on this known issue.