这个Hello World风格的swf如何导致大量内存泄漏?

时间:2014-06-20 15:52:16

标签: actionscript-3 flash memory-leaks camera garbage-collection

制作一个swf,通过IE运行它,并观察你的内存不断增长 - 甚至可能出现猛涨 - 原因似乎超出了Flash程序员的控制范围:

package
{
    import flash.display.Sprite;
    import flash.events.*;
    import flash.media.*;
    import flash.net.*;
    import flash.utils.Timer;

    public class HelloCam extends Sprite
    {
        private var m_tmr:Timer = new Timer(5000, 1);

        public function HelloCam()
        {
            stage ? init() : addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(pEvent:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            (addChild(new Video()) as Video).attachCamera(Camera.getCamera());

            m_tmr.addEventListener(TimerEvent.TIMER, onTimer);
            m_tmr.start();
        }

        private function onTimer(pEvent:TimerEvent):void
        {
            removeEventListener(TimerEvent.TIMER, onTimer);
            navigateToURL(new URLRequest("http://someIP/HelloCam.swf"), "_self");
        }
    }
}

这不是一个特定程序的孤立。我们一直在处理一个问题,该问题始于更大的软件,如果您有Camera个对象和Video对象,则向用户提供本地Feed,并继续执行重定向在同一个网站上,存在严重的内存泄漏。

(在某些机器上比在其他机器上更糟糕,但它就在那里。我们也看到过这样的情况,它会打到门槛,稍微回过头来,然后在没有进一步阻碍的情况下从那里飙升。)

我们尝试了几种方法,包括将浏览器包装在.NET程序中并通过.NET处理刷新,而不是通过Flash处理。我们已经切换了网站在不同刷新时会做的不同事情。所有这些。

这是Flash的核心和它的目标,所以有什么方法(希望除了使用调试swfs和Flash播放器)来阻止这样的内存泄漏,或者Adobe / Microsoft真的这么草率?

2 个答案:

答案 0 :(得分:1)

此代码中没有任何内容会导致内存泄漏。它可能是或可能不是IE问题。虽然我觉得很奇怪你每隔5秒自己“刷新”一次应用程序,但这不是一个优雅的解决方案。

现在要真正了解泄漏的来源,您需要对SWF进行分析。我建议使用Adobe Scout ,它会为您提供详细的分析,如内存,CPU时间,垃圾收集运行等。

我认为这是您真正了解导致内存泄漏的唯一方法,因为您需要记住Flash在虚拟机中运行,因此可能是导致内存泄漏的其他SWF。此外,您每次都在重新加载应用程序并制作新相机。可能只是垃圾收集器不经常运行,并且在VM决定运行GC时,内存会被分配到某个点。

答案 1 :(得分:0)

这是一个IE问题,而不是一个Flash问题。无论是正常使用IE还是通过带有WebBrowser对象的.NET程序,都是如此。

话虽这么说,我们遇到的代码涉及在VB.NET中使用WebBrowser对象,我们通过.NET代码处理大部分刷新和重定向,而不是Flash代码。因此,如果你要从问题中的Flash代码中刷新,然后将它们重新定位到.NET代码中,这是一个没有内存泄漏的简短示例:

Option Explicit On
Option Strict On

Imports System.IO
Imports System.Runtime.InteropServices

Public Class Form1

    <DllImport("KERNEL32.DLL", EntryPoint:="SetProcessWorkingSetSize", SetLastError:=True, CallingConvention:=CallingConvention.StdCall)> _
    Friend Shared Function SetProcessWorkingSetSize(pProcess As IntPtr, dwMinimumWorkingSetSize As Integer, dwMaximumWorkingSetSize As Integer) As Boolean
    End Function

    <DllImport("KERNEL32.DLL", EntryPoint:="GetCurrentProcess", SetLastError:=True, CallingConvention:=CallingConvention.StdCall)> _
    Friend Shared Function GetCurrentProcess() As IntPtr
    End Function

    Private Const URL As String = "http://someIP/HelloCam.swf"

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ws.Url = New Uri(URL)
        Timer1.Interval = 5000
        Timer1.Start()
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1)
        ws.Url = New Uri(URL)
    End Sub
End Class

诀窍是:

  1. Kernel32.dll的{​​{1}}和SetProcessWorkingSetSize(IntPtr, Integer, Integer)函数建立DLL导入。

  2. 重复调用GetCurrentProcess(),或者在重定向的同时或者单独调整时间。

  3. IE / .NET中的WebBrowser对象有内部内存泄漏,但是这个解决方案通过告诉操作系统介入并参与其中来解决问题。通过将SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1)传递给-1的第二个和第三个参数,可以使该函数以特殊模式运行,该模式检查进程内存中的所有页面,然后删除被认为的那些页面不必要。通常这可能不是解决内存泄漏的最佳方法,但由于API类内部存在问题,因此在这种情况下它可能是一个好主意。

    感谢Creative Magic的answer and comment,以及学习this question的答案。