创建StageWebView实例时,如果在多个站点之间切换,您会注意到所使用的内存量会慢慢增加。如果您正在查看2/3站点,这不是问题,但是当创建带有内置浏览器的AIR应用程序时,我现在在内存管理方面遇到了障碍
无论我做什么
问题仍然存在。网页的每次加载都会使内存增加3mb,逐渐增加到1gb以上并使应用程序崩溃。
我在StageWebView实例上没有事件监听器。我完全没有提到它。第二个URL加载后,内存不会完全重置。
通过在AIR中运行以下内容可以看出这一点:
package kazo
{
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.media.StageWebView;
import mx.controls.Button;
import mx.core.UIComponent;
import flash.system.System;
/**
* ...
* @author KM
*/
public class Controller extends UIComponent
{
private var stageWeb:StageWebView;
private var url:uint = 0;
private const URL_ARRAY:Array = [
'http://www.mmo-champion.com/',
'http://www.bbc.co.uk/news/',
'http://www.twitch.tv/riotgames/',
'http://www.stackoverflow.com/'
]
/**
*
*/
public function Controller()
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
/**
*
* @param e
*/
private function init(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
stageWeb = new StageWebView();
stageWeb.stage = stage;
stageWeb.viewPort = new Rectangle(0, 80, width, height - 50);
var btn:Button = new Button();
addChild(btn);
btn.label = 'Load URL';
btn.x = 0;
btn.y = 10;;
btn.width = 100;
btn.height = 30;
btn.addEventListener(MouseEvent.CLICK, load);
btn = new Button();
btn.label = 'Try to GC';
btn.x = 150;
btn.y = 10;;
btn.width = 100;
btn.height = 30;
addChild(btn);
btn.addEventListener(MouseEvent.CLICK, tryGC);
/// 26,576k
}
/**
*
* @param e
*/
private function load(e:MouseEvent):void {
if (!stageWeb) {
stageWeb = new StageWebView();
stageWeb.stage = stage;
stageWeb.viewPort = new Rectangle(0, 80, width, height - 50);
}
stageWeb.loadURL(URL_ARRAY[url % 4]);
url++;
}
/**
*
* @param e
*/
private function tryGC(e:MouseEvent):void {
stageWeb.stage = null;
stageWeb.viewPort = null;
stageWeb.dispose();
stageWeb = null;
System.gc();
}
}
}
有没有人有这方面的经验?
答案 0 :(得分:2)
我对您的代码进行了一些小的更改,使其可以与AIR 14 SDK(ASC 2.0,没有flex)兼容,我构建&用
测试空气应用 mxmlc -optimize=true +configname=air Controller.as && adl Controller.xml
并观看Adobe Scout的内存使用情况
GC稳定后的记忆,稳定在14481 kB
您可以向mxmlc添加-advanced-telemetry=true
选项以精确跟踪分配/解除分配,只需考虑推送"隐藏已清理的对象"切换并选择两个GC之间的范围。你会看到一些物体没有立即释放,但你也会看到,如果你同时选择其中几个范围,那些临时泄漏就不会加起来,这就解释了为什么内存不会不断增加, GC环境,内存泄漏并不是真正的内存泄漏
如何衡量内存使用情况?
我检查了adl进程的内存使用情况,它更高(> 100MB)并且不太稳定,但在GC之后仍然稳定在110到120MB之间。在任何情况下,它肯定看起来不会增加到1 GB
请记住,ActionScript GC是惰性的并保留对象池以供将来重用,任何比hello world更多的应用程序有时会出现奇怪的内存行为,这是AVM2工作方式的一部分。
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.media.StageWebView;
import flash.system.System;
import flash.text.TextField;
/**
* ...
* @author KM
*/
public class Controller extends Sprite
{
private var stageWeb:StageWebView;
private var url:uint = 0;
private const URL_ARRAY:Array = [
'http://www.mmo-champion.com/',
'http://www.bbc.co.uk/news/',
'http://www.twitch.tv/riotgames/',
'http://www.stackoverflow.com/'
]
/**
*
*/
public function Controller()
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
/**
*
* @param e
*/
private function init(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
stageWeb = new StageWebView();
stageWeb.stage = stage;
stageWeb.viewPort = new Rectangle(0, 80, stage.stageWidth, stage.stageHeight - 50);
var btn:TextField = new TextField();
btn.selectable = false;
addChild(btn);
btn.text = 'Load URL';
btn.x = 0;
btn.y = 10;;
btn.width = 100;
btn.height = 30;
btn.addEventListener(MouseEvent.CLICK, load);
btn = new TextField();
btn.selectable = false;
btn.text = 'Try to GC';
btn.x = 150;
btn.y = 10;;
btn.width = 100;
btn.height = 30;
addChild(btn);
btn.addEventListener(MouseEvent.CLICK, tryGC);
/// 26,576k
}
/**
*
* @param e
*/
private function load(e:MouseEvent):void {
if (!stageWeb) {
stageWeb = new StageWebView();
stageWeb.stage = stage;
stageWeb.viewPort = new Rectangle(0, 80, stage.stageWidth, stage.stageHeight - 50);
}
stageWeb.loadURL(URL_ARRAY[url % 4]);
url++;
}
/**
*
* @param e
*/
private function tryGC(e:MouseEvent):void {
stageWeb.stage = null;
stageWeb.viewPort = null;
stageWeb.dispose();
stageWeb = null;
System.gc();
}
}
}
答案 1 :(得分:0)
这只是一个随意的路人的想法 ramblings ..注意:我没有测试运行你的代码,因为此时我还没有访问Flash。我也不会100%支持我的漫步(我知道这是一个WTF?但请继续阅读,希望在那里有用的东西......)
在你的函数tryGC(e:MouseEvent):void
中设置stageWeb = null;
这很好,但是在你的函数load(e:MouseEvent):void
中你说“如果stageWeb为null则再创建一个”。好吧,因为你以前设置Flash考虑一个null
它乖乖地在内存中创建一个新的(旧的内存印记仍然可能还没有垃圾收集(只是在它的队列中)因此它看起来像ram使用已经增加。
如果您之后要立即加载其他页面,那么整个tryGC
事情就有点瑕疵。垃圾收集(可能)从未发生过,因为周围还有一个鼠标事件,if (!stageWeb) { //etc }
所以基本上你将其状态转换为null
,但它无法被真正删除,因为其他东西正在使用引用它可以在将来的任何时候被调用,所以它只是在内存中存在(具有null
状态)..
可能的解决方案:
1)在您的函数tryGC
中删除加载网址的鼠标侦听器
private function tryGC(e:MouseEvent):void {
stageWeb.stage = null;
stageWeb.viewPort = null;
stageWeb.dispose();
stageWeb = null;
btn.removeEventListener(MouseEvent.CLICK, load);
System.gc();
}
现在等几秒钟检查ram的使用量是否减少了?如果在尝试GC之前它有助于加载至少10个以上的网址,因为您无法通过点击加载网址。这仅用于测试以查看mouselistener是否是垃圾收集器的问题
2)您真正需要的是清除/覆盖当前网址内容/缓存的方法...不重新创建新的HTML网页浏览量。在这种情况下,这没有任何帮助。我认为你的问题也源于此... History Forward/Back ...我怀疑每个网址负载都会添加到历史记录中,而历史记录又更像是一个“内容缓存”而不仅仅是“以前的字符串” URL”。
考虑一下您对BAT文件的计划......那么打开100个网址,依次缓存它们,但您的视口一次只显示一个项目(其他99个页面保存在内存中,满载并准备就绪用于即时显示..)。我不知道解决方法。没有stageWeb.unloadURL();
甚至stageWeb.clearCache();
我看起来不够努力,但是这个星球上的某个人知道一个关于它的博客(并且希望)......