我的 Android 4.0.4 应用程序包含一个 WebView,用户可以通过它查看本地存储在 Assets 目录中的多个页面。循环浏览页面时,最终会触发以下错误并且应用程序崩溃:
问题似乎与此处报告的问题有关:
我已使用以下链接中提供的内存分析器工具插件说明来检查详细信息:
http://therockncoder.blogspot.ca/2012/09/fixing-android-memory-leak.html
结果如下所示(还不能发布屏幕截图,所以文本必须这样做):
MAT 摘录
Class Name | Shallow Heap | Retained Heap | Percentage
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| | |
java.lang.Thread @ 0x40daa320 Thread-39775 Thread | 80 | 15,310,552 | 76.74%
|- byte[32768] @ 0x40d5a8d0 <!DOCTYPE html>.<html xml:lang="">.<head>. <title>Android Test-HTML5-480PX-Page 0</title>. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />. <meta name="viewport" content="width=360, height=480">. <!--. <meta name="viewport" co...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x40e25bb8 on-play-state: running;. -webkit-animation-timing-function: step-start;. }. @-webkit-keyframes ag16780-anim45051. {. 0.000% { background-position:0px 0px,77px 0px,77px 0px,77px 0px,77px 0px,77px 0px; }. 20.000% { background-position...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x40e60520 //<![CDATA[.var pageParams = new Object();.pageParams['readMode'] = 1;...function applyReadMode().{. var audioNodes = document.getElementsByClassName('BGAudio');. for (var i=0; i<audioNodes.length; i++). {. .if (pageParams['readMode'] == 0). ...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x40e86f48 .PNG........IHDR....... ......U......gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<....bKGD..............pHYs...#...#.x.?v...ZIDATH..U]l\W..f.9.......8..G.....Z$ZUi..*EQQ...RE.Hi.D".0BTj..J.x..O.J..C.)..IU.R......HB.8..&..\.x..w..{fx...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x40f09f00 html.{. padding : 0px 0px 0px 0px;. margin : 0px 0px 0px 0px;. height : 100%;. width : 100%;. background : #ffffff;.}.body.{. padding : 0px 0px 0px 0px;. margin : 0px 0px...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x40f11f18 .=Xt.....H...hE:t.;.......=.s....f.(.....v.5'<.8}=.=kXF..&&...K...j.........<...A..........}.......c.c..7.e{b.....O.p..h....e.1....8.zd{..........}3.Z.W..v.|}y.u...3M.....h2IDAT...........Z.;u..M.....'!.(.S.....|j.]..h.l7.... .....I...u.&J5.";9.d04.S.........| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41009af0 //<![CDATA[.var pageParams = new Object();.pageParams['readMode'] = 1;...function applyReadMode().{. var audioNodes = document.getElementsByClassName('BGAudio');. for (var i=0; i<audioNodes.length; i++). {. .if (pageParams['readMode'] == 0). ...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41011b08 html.{. padding : 0px 0px 0px 0px;. margin : 0px 0px 0px 0px;. height : 100%;. width : 100%;. background : #ffffff;.}.body.{. padding : 0px 0px 0px 0px;. margin : 0px 0px...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41019b20 ...t.%#2#b......0..0.6.....A.M....%.F,.*...(.>.q$_.0... a..sF...."Ypn"....#.q...@...........C...3....-.L.b.A).F....4.....Q.1.Wd..3.|.Y%........:.w.F~ ]..0i>a......4n.E7.O..+.7S...D...|.IDAT..'...<.....E.n...!.1.....Tx211..E....4 .*f....>..)..)...gS.j.. WX....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41021b38 .PNG........IHDR...|.................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<....PLTE.................................................................................................................................................| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41029b50 .PNG........IHDR.......Q.......0.....gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<....bKGD..............pHYs...#...#.x.?v..:.IDATx...gx...........-.....4...p...S....%$!$.$$....z....8T.:.L...c..wI......23..3....U...?.5..j.......J@.P....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41031b68 .PNG........IHDR...V.........0..X....gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<....bKGD..............pHYs...#...#.x.?v....IDATh..Zyp.U....f.;3....j0..p...E]...M...*%..,.J..Pb..,....Z.AE.E.....n.."A.........@..d...>...........W......| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410889d0 .PNG........IHDR.............a.~e....gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<....PLTE...Q_HRgL......=I93?/f~Zg~[DV=@P8)0$'2&(3&/<('1$......""!:;:"#"......)3&...............&&&'''.......... ...........$.677888.$....................| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410909e8 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...wPLTE........~..............v...........~.........{yn........................................................F.. ..4..............!...........+..l....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41098a00 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...wPLTE...uuj....................i.......................................................................S..'..$..............*..............[..........| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410a0a18 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...tPLTE...llh...........................|.u.....................................................]..*..+..............-..............T..............M....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410a8a30 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...wPLTE...ooi.......................}....................................................................[..)..%..............+..............Y..........| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410b0a48 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...zPLTE...wvk.......................{....................................................................\..(..$..............,..............\..........| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410b8a60 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...zPLTE...rqg.....d...................................z........................................................R..%.. ..............(..............]....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410c0a78 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...wPLTE...rrh........r............................................................................................Q..%.. ..............(................| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410c8a90 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...wPLTE........}..............O...........|.........xwl........................................................G..!.....8.............."...........'....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410d0aa8 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...zPLTE........~..............m...........~.........{yn........................................................F.. ..4..............!...........+..l....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410d8ac0 .PNG........IHDR.............e.. ....gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...yPLTE...mmmhfZ........h.................)........c..kppp..h..u.......................................................................x..o..a..........| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410e0ad8 .PNG........IHDR.............e.. ....gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<....PLTE...hhh.......................-...........e..~........|.............................................................................s.............| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410e8af0 .PNG........IHDR.............e.. ....gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...|PLTE.........,,+........c..~...........]..............y....................n.........................................................................| 32,784 | 32,784 | 0.16%
'- Total: 25 of 471 entries; 446 more | | |
android.widget.HorizontalScrollView @ 0x40e1d8b8 | 576 | 978,456 | 4.90%
class android.content.res.Resources @ 0x40ab1570 System Class | 48 | 266,432 | 1.34%
...
日志摘录
...
10-08 22:10:28.970: D/MediaPlayer(9823): pause() out
10-08 22:10:29.090: E/dalvikvm(9823): JNI ERROR (app bug): local reference table overflow (max=512)
10-08 22:10:29.090: W/dalvikvm(9823): JNI local reference table (0x2498270) dump:
10-08 22:10:29.090: W/dalvikvm(9823): Last 10 entries (of 512):
10-08 22:10:29.090: W/dalvikvm(9823): 511: 0x40d696d0 android.content.res.AssetManager
10-08 22:10:29.090: W/dalvikvm(9823): 510: 0x4201eab0 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 509: 0x42016a98 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 508: 0x4200ea80 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 507: 0x42006a68 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 506: 0x41ffea50 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 505: 0x41ff6a38 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 504: 0x41feea20 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 503: 0x41fe6a08 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 502: 0x41fde9f0 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): Summary:
10-08 22:10:29.090: W/dalvikvm(9823): 1 of java.lang.Class
10-08 22:10:29.090: W/dalvikvm(9823): 510 of byte[] (32768 elements) (510 unique instances)
10-08 22:10:29.090: W/dalvikvm(9823): 1 of android.content.res.AssetManager
10-08 22:10:29.090: E/dalvikvm(9823): Failed adding to JNI local ref table (has 512 entries)
10-08 22:10:29.090: I/dalvikvm(9823): "Thread-39898" prio=5 tid=12 RUNNABLE
10-08 22:10:29.090: I/dalvikvm(9823): | group="main" sCount=0 dsCount=0 obj=0x40d6b9d8 self=0x222a030
10-08 22:10:29.090: I/dalvikvm(9823): | sysTid=9871 nice=0 sched=0/0 cgrp=default handle=29456640
10-08 22:10:29.090: I/dalvikvm(9823): | schedstat=( 520906000 142824000 757 ) utm=22 stm=30 core=2
10-08 22:10:29.090: I/dalvikvm(9823): at android.content.res.AssetManager.readAsset(Native Method)
10-08 22:10:29.090: I/dalvikvm(9823): at android.content.res.AssetManager.access$700(AssetManager.java:35)
10-08 22:10:29.090: I/dalvikvm(9823): at android.content.res.AssetManager$AssetInputStream.read(AssetManager.java:648)
10-08 22:10:29.090: I/dalvikvm(9823): at dalvik.system.NativeStart.run(Native Method)
10-08 22:10:29.090: E/dalvikvm(9823): VM aborting
10-08 22:10:29.090: A/libc(9823): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1)
10-08 22:10:29.140: I/MediaPlayer(9823): setLPAflag() in
...
通过查看 MAT 条目,主线程似乎持有对所有 HTML 页面、CSS 和 Javascript 文件、图像和音频文件的引用,并且不会释放它们。最终,当调用一个新的 URL 时,AssetManager 会尝试写入超出 JNI 本地引用表边界(512 个条目)的条目,耗尽可用空间并导致内存泄漏。
我尝试了各种方法来防止保留引用,但没有成功。这包括:
初始化 WebView,使其不缓存页面:
mWebView.getSettings().setAppCacheEnabled(false);
mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
mWebView.setDrawingCacheEnabled(false);
尝试在加载下一页之前删除所有现有的 WebView 数据:
mWebView.stopLoading();
mWebView.clearCache(true);
mWebView.destroyDrawingCache();
mWebView.clearHistory();
mWebView.freeMemory();
mWebView.getInstance().deleteAllData();
动态创建 WebView 而不是通过 res/layout XML,并为其分配应用程序上下文而不是 Activity 上下文:
mWebView = new WebView(getApplicationContext());
在更改页面之前销毁当前的 WebView 并为下一页动态创建一个新的 WebView,但这除了减慢应用程序之外没有任何影响; JNI 本地表仍然保留旧引用:
mWebViewContainer.removeViewAt(0);
mWebView.destroyDrawingCache();
mWebView.destroy();
mWebView = null;
System.gc();
理想的做法是在加载下一页之前删除 JNI 表中的旧条目,但我发现没有办法做到这一点——一旦调用了 URL,无论发生什么, Assets 目录引用都会保留我试过了。也许我遗漏了一些东西,或者在以后的 Android 版本中有待修复?如果做不到这一点,即使为每个页面销毁和创建新的 WebView 会对性能产生负面影响并且会使设计复杂化,如果页面可以在它们自己的线程中创建并保存它们自己的 Assets 引用而不是主线程,也许这会起作用(前提是这些线程可以在页面更改期间停止)。
更新
我尝试在单独的线程中创建 WebView,但出现错误“必须在 UI 线程上调用所有 WebView 方法。 future 版本的 WebView 可能不支持在其他线程上使用。”。我假设“UI 线程”指的是主线程。这篇文章似乎支持这一点:
最佳答案
我想出了一个解决方法,可以避免内存泄漏,但代价是存储的数据量翻倍。基本上 Assets 目录的所有内容都必须复制到内部或外部存储,而 HTML 页面必须从这些存储目录加载到 WebView。
内部存储
外部存储
以下是将指定目录/子目录的内容从 Assets 文件夹传输到存储(在本例中为内部)的示例方法。如果遇到子目录,会递归调用下钻。种子调用必须通过 "" 作为 sourceDirName。
注意:如所写,仅适用于深度为 1 的子目录,并且文件通过包含“.”与目录区分开来。名称和扩展名之间的字符——如果这个不适合你,你可能需要使用不同的测试。不可能对 Assets 成员使用 if (new File(sourceFileNames[i]).isDirectory()) 这样的测试,因为它们不是真正的文件;来自 AssetManager 文档:“文件 ... 已作为简单的字节流与应用程序 bundle 在一起。”
private void copyAssetsToStorage(String sourceDirName)
{
// /data/data/com.package.name/files
try
{
String[] sourceFileNames = mContext.getAssets().list(sourceDirName);
File targetDir = mContext.getFilesDir();
if (sourceDirName != "")
{
sourceDirName += "/";
targetDir = new File(targetDir, sourceDirName);
targetDir.mkdir();
}
targetDir.setReadable(true, false);
if (sourceFileNames != null)
{
byte[] buffer;
int length;
InputStream inStream;
File outFile;
FileOutputStream outStream;
for (int i = 0; i < sourceFileNames.length; i++)
{
if (sourceFileNames[i].contains(".") == false)
{
// Recursive call to drill down
copyAssetsToStorage(sourceFileNames[i]);
}
else
{
inStream = mContext.getAssets().open(
sourceDirName + sourceFileNames[i]);
outFile = new File(targetDir, sourceFileNames[i]);
outStream = new FileOutputStream(outFile, false);
buffer = new byte[8192];
while ((length = inStream.read(buffer)) > 0)
{
outStream.write(buffer, 0, length);
}
inStream.close();
inStream = null;
outStream.flush();
outStream.close();
outStream = null;
outFile.setReadable(true, false);
}
}
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
} // copyAssetsToStorage
关于Android WebView Assets 引用内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12803309/
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序
我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的rubyyaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir
你好,我无法成功如何在散列中删除key后释放内存。当我从哈希中删除键时,内存不会释放,也不会在手动调用GC.start后释放。当从Hash中删除键并且这些对象在某处泄漏时,这是预期的行为还是GC不释放内存?如何在Ruby中删除Hash中的键并在内存中取消分配它?例子:irb(main):001:0>`ps-orss=-p#{Process.pid}`.to_i=>4748irb(main):002:0>a={}=>{}irb(main):003:0>1000000.times{|i|a[i]="test#{i}"}=>1000000irb(main):004:0>`ps-orss=-p
我正在尝试将一个资源属性的默认值设置为另一个属性的值。我正在为我正在构建的tomcat说明书定义一个资源,其中包含以下定义。我想要可以独立设置的“名称”和“服务名称”属性。当未设置服务名称时,我希望它默认为为“名称”提供的任何内容。以下不符合我的预期:attribute:name,:kind_of=>String,:required=>true,:name_attribute=>trueattribute:service_name,:kind_of=>String,:default=>:name注意第二行末尾的“:default=>:name”。当我在Recipe的新block中引用我
如thisanswer中所述,Array.new(size,object)创建一个数组,其中size引用相同的object。hash=Hash.newa=Array.new(2,hash)a[0]['cat']='feline'a#=>[{"cat"=>"feline"},{"cat"=>"feline"}]a[1]['cat']='Felix'a#=>[{"cat"=>"Felix"},{"cat"=>"Felix"}]为什么Ruby会这样做,而不是对object进行dup或clone? 最佳答案 因为那是thedocumenta
这会导致Ruby出现内存问题吗?我知道如果大小超过10KB,Open-URI会写入TempFile。但是HTTParty会在写入TempFile之前尝试将整个PDF保存到内存吗?src=Tempfile.new("file.pdf")src.binmodesrc.writeHTTParty.get("large_file.pdf").parsed_response 最佳答案 您可以使用Net::HTTP。参见thedocumentation(特别是标题为“流媒体响应机构”的部分)。这是文档中的示例:uri=URI('http://e
假设我有一个可枚举对象enum,现在我想获取第三个项目。我知道一种通用方法是转换成数组,然后使用索引访问,如:enum.to_a[2]但这种方式会创建一个临时数组,效率可能很低。现在我使用:enum.each_with_index{|v,i|breakvifi==2}但这非常丑陋和多余。执行此操作最有效的方法是什么? 最佳答案 你可以使用take剥离前三个元素,然后剥离last从take给你的数组中获取第三个元素:third=enum.take(3).last如果您根本不想生成任何数组,那么也许:#Ifenumisn'tanEnum
代码:threads=[]Thread.abort_on_exception=truebegin#throwexceptionsinthreadssowecanseethemthreadseputs"EXCEPTION:#{e.inspect}"puts"MESSAGE:#{e.message}"end崩溃:.rvm/gems/ruby-2.1.3@req/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:478:inload_missing_constant':自动加载常量MyClass时检测到循环依赖稍加研究后,
在部署在heroku上的Rails应用程序(v:3.1)中,我在内存中获得了更多具有相同ID的对象。我的heroku控制台日志:>>Project.find_all_by_id(92).size=>2>>ActiveRecord::Base.connection.execute('select*fromprojectswhereid=92').to_a.size=>1这怎么可能?可能是什么问题? 最佳答案 解决方案根据您的SQL查询,您的数据库中显然没有重复条目。也许您的类项目中的size或length方法已被覆盖。我试过find_