Javascript内存泄漏与谷歌地图'Map.panTo()方法

Javascript Memory Leak with Google Maps' Map.panTo() Method

本文关键字:panTo Map 方法 泄漏 内存 谷歌地图 Javascript      更新时间:2023-09-26

我一直在经历Javascript内存不足错误与Web应用程序加载谷歌地图,并不断地从一个点平移到另一个点。它大约需要半天的时间才会耗尽内存,但我真的希望它能持续更长时间。我已确定在映射时发生内存泄漏。尽管使用了panTo方法我非常怀疑这可能是我使用它的方式(Javascript不是我的强项)套装)。你能看看这段代码并帮我修复这个内存泄漏吗?为了在调试期间节省时间,我加快了演示代码中它移动的间隔(即使在Windows任务管理器中检查进程,泄漏也是明显的)。它运行在asp.net 3.5 Web Forms上,但是没有回发,代码完全是HTML、CSS和Javascript。它在IE中泄漏最严重(我需要用它来显示这个)。

编辑:

    我已经尝试使用不同版本的谷歌地图API(2,3.0和3.6)。
  1. 我知道我不需要将示例代码中的映射放入Hashtable或Array中,但这并不影响内存泄漏。
  2. 我试图避免黑客攻击,例如每隔一段时间刷新页面或使用静态谷歌地图API。
  3. 赏金将给谁弄清楚如何修复内存泄漏或谁清楚地识别并证明为什么它不能被修复(如果是这种情况)。

代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Map Shifter</title>
    <style type="text/css">
        #divMap { height: 400px; width:400px; position:absolute; top:10%; left:10%; border: 2px solid #ff1100; }    
    </style>
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?v=2&sensor=false"></script>
    <script type="text/javascript" language="javascript">
        //Have tried both HashTable and Array (Both Leak)...
        var m_arrMaps = new HashTable(); //new Array();
        var m_Timer;
        function HashTable() {
            return this;
        }
        function LoadMapAndStartShifting() {
            var objMapCenterPoint = new google.maps.LatLng(20.5, -156);
            var objMapOptions = { zoom: 9, center: objMapCenterPoint, mapTypeId: google.maps.MapTypeId.ROADMAP,
                scaleControl: false, streetViewControl:false, zoomControl: false, mapTypeControl: false, panControl: false
            }
            var map = new google.maps.Map(document.getElementById("divMap"), objMapOptions);
            m_arrMaps["ShiftingMap"] = map;
            setTimeout("ShiftMap(20.5, -156);", 700);
        }
        function ShiftMap(decLat, decLng) {
            var objLatLong = new google.maps.LatLng(decLat, decLng);
            //Have tried setCenter instead of preferred panTo and it still leaks!
            m_arrMaps["ShiftingMap"].panTo(objLatLong);
            if (decLat == 20.5) {
                //Leaks...
                ResetTimer(39, -87);
            }
            else {
                //Still leaks...
                setTimeout("ShiftMap(20.5, -156);", 700);
            }
        }
        function ResetTimer(decLat, decLng) {
            m_Timer = setTimeout("ShiftMap(" + decLat + ", " + decLng + ");", 700);    
        }    
    </script>
</head>
<body onload="LoadMapAndStartShifting();">
    <form id="form1" runat="server">
    <div id="divMap"></div>
   </form>
</body>

为什么要为映射创建哈希表?您可以直接将map创建为全局变量。我会很惊讶这有什么不同,但你的评论是"//尝试过HashTable和Array(两者都泄漏)…"让我想知道为什么你需要一个HashTable或数组。

您还可以通过直接将选项的结构传递给Map()函数来摆脱objMapOptions和objMapCenterPoint变量,同样地,将latLng传递给panTo()函数。

<script type="text/javascript" language="javascript">
    var m_Timer, map;
    function LoadMapAndStartShifting() {
        map = new google.maps.Map(document.getElementById("divMap"), { zoom: 9, center: new google.maps.LatLng(20.5, -156), mapTypeId: google.maps.MapTypeId.ROADMAP,
            scaleControl: false, streetViewControl:false, zoomControl: false, mapTypeControl: false, panControl: false
        });
        setTimeout("ShiftMap(20.5, -156);", 700);
    }
    function ShiftMap(decLat, decLng) {
        map.panTo(new google.maps.LatLng(decLat, decLng));
        if (decLat == 20.5) {
            //Leaks...
            ResetTimer(39, -87);
        }
        else {
            //Still leaks...
            setTimeout("ShiftMap(20.5, -156);", 700);
        }
    }
    function ResetTimer(decLat, decLng) {
        m_Timer = setTimeout("ShiftMap(" + decLat + ", " + decLng + ");", 700);    
    }    
</script>

另一个建议,缓存映射怎么样?我不知道这个示例代码是否真的是你在做的,但如果它只是以这种方式在两个地图之间切换,你就不能使用静态地图api,缓存图像,然后使用javascript旋转图像吗?

我又有了一个想法。指定v=2,即获取该API的版本2。当前版本是3.6。建议您尝试更新版本号(或者只是删除v参数以获得最新的稳定版本),看看是否会有所改善。可能他们已经在最近的版本中整理了垃圾收集。

看起来您只在"Hashtable"对象中存储一个元素-["ShiftingMap"] -它不包含映射,它包含一个映射。您可以使用全局变量来保存map对象。

唯一重复的分配是为每个pan创建的new google.maps.LatLng(decLat, decLng)

建议:

1) LatLng的文档没有给出任何需要显式释放对象的警告,因此可能应该由垃圾收集器处理。

2)考虑整体问题——你试图连续移动谷歌地图6个小时或更长时间。你为什么认为漏洞在你的代码里?问题更有可能出在G Maps上。可能下载的地图图像块保存在本地,因为用户可能会想要向后平移。

作为测试,试着在两个点之间来回移动,而不是当前的全球移动。(如果我对你的相对移位理解正确的话)

查看泄漏是否以内存/小时的速率发生

3)一定要看看不同的浏览器对你的问题是否有不同的影响。试试Google Chrome。

添加

我重新编写了演示代码,将LatLng调用移出循环,但它仍然泄漏。此外,最好在setTimeout调用中使用非字符串值,所以我也改变了这一点。我还使用Maps API教程将doctype设置为他们推荐的类型。

结果如下。它在FF和Chrome上泄漏。我在Google Maps API v3官方论坛上发表了一篇文章。

很明显,.panTo方法泄漏了。我猜你的下一步是看谷歌人是否回复你的帖子。

测试用例演示

重做的测试用例:

<!DOCTYPE html>
<html>
<!-- http://sandbox.kluger.com/map_demo.html -->
<!-- See tutorial http://code.google.com/apis/maps/documentation/javascript/tutorial.html -->
<head>
    <title>Map Shifter</title>
    <style type="text/css">
        #divMap { height: 400px; width:400px; position:absolute; top:10%; 
                  left:10%; border: 2px solid #ff1100; } 
    </style>
    <script type="text/javascript" 
            src="http://maps.google.com/maps/api/js?sensor=false"></script>
    <script type="text/javascript" language="javascript">
        // Globals
        var map,
            mapCenterPoints,
            currentPoint;
        var ShiftMap = function() {
            currentPoint = currentPoint == 0 ? 1 : 0; // update
            map.panTo(mapCenterPoints[currentPoint]);
            setTimeout(ShiftMap, 700);           
        }
        function LoadMapAndStartShifting() {
            mapCenterPoints = [new google.maps.LatLng(20.5, -156),
                               new google.maps.LatLng(39, -87)];
            currentPoint = 0;
            var objMapOptions = { zoom: 9, 
                                  center: mapCenterPoints[currentPoint], 
                                  mapTypeId: google.maps.MapTypeId.ROADMAP,
                                  scaleControl: false, streetViewControl:false, 
                                  zoomControl: false, mapTypeControl: false, 
                                  panControl: false
            }
            map = new google.maps.Map(document.getElementById("divMap"), 
                        objMapOptions);
            setTimeout(ShiftMap, 700);
        }
    </script>
</head>
<body onload="LoadMapAndStartShifting();">
      <div id="divMap"></div>
</body>
</html>

您可以尝试在使用JavaScript遍历数据后刷新页面。这可能会释放页面上运行的脚本正在使用的内存:

如何在JavaScript/jQuery重定向到另一个网页?