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

时间:2011-09-16 15:00:23

标签: javascript asp.net google-maps memory-leaks

我一直在使用Web应用程序遇到Javascript Out of Memory错误,该应用程序加载Google Map并从一个点连续平移到另一个点。它需要大约半天才能耗尽内存,但我真的希望它能持续更长时间。一世 已经确定使用map.panTo方法时会发生内存泄漏 我非常怀疑它可能是我使用它的方式(Javascript不是我强大的 适合)。你能看一下这段代码并帮我修复这个内存泄漏吗?为了节省调试时间,我加快了它在这个演示代码中的间隔(即使通过检查Windows任务管理器中的过程,泄漏也很明显)。这使用ASP .Net 3.5 Web窗体,但没有PostBacks,代码完全是HTML,CSS和Javascript。它泄漏了IE中最糟糕的情况(我需要用它来显示它)。

修改

  1. 我尝试使用不同版本的Google Maps API(2,3.0和3.6)。
  2. 我知道我不需要将示例代码中的映射放入Hashtable或Array中,但这不会影响内存泄漏。
  3. 我正在尝试避免黑客攻击,例如经常刷新页面或使用静态Google Maps API。
  4. Bounty将会找出如何解决内存泄漏或明确识别并证明无法解决的原因(如果是这种情况)。
  5. 代码:

    <!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>
    

4 个答案:

答案 0 :(得分:2)

为什么要为地图创建哈希表?您可以将地图创建为全局变量。我会感到惊讶,但是你的评论“//已经尝试了HashTable和Array(两个泄漏)......”让我想知道为什么你需要哈希表或数组。

你也可以通过将选项结构直接传递给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旋转图象?

答案 1 :(得分:2)

看起来你只在“Hashtable”对象中存储了一个元素 - [“ShiftingMap”] - 它不是持有地图,而是持有一张地图。您可以使用全局变量来保存地图对象。

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

建议:

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

2)考虑整体问题 - 您尝试连续平移Google地图6小时或更长时间。为什么你认为泄漏在你的代码中?这个问题更有可能出现在G Maps中。可能下载的地图图像切片保存在本地,因为用户可能想要反击。

作为测试,尝试在两点之间来回平移,而不是在全球范围内进行当前平移。 (如果我理解你的相对转移是正确的。)

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

3)请务必查看不同的浏览器是否会以不同方式影响您的问题。 Esp尝试Google Chrome。

<强>加

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

结果如下。它泄露在FF和Chrome上。我在官方Google Maps API v3 forum提交了一个帖子。

.panTo方法漏洞似乎很明显。我想你的下一步是看看Google员工是否回复帖子。

Test case demo

重写测试用例:

<!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>

答案 2 :(得分:2)

刚才有另一个想法。您指定v = 2,即获取此API的版本2发行版。目前的版本是3.6。建议您尝试更新版本号(或者只是删除v参数以获取最新的稳定版本)并查看是否可以改进版本。可能他们在最近的版本中整理了任何垃圾收集。

答案 3 :(得分:1)

使用JavaScript循环访问数据后,您可以尝试刷新页面。这可能会释放页面上运行的脚本使用的内存:

How to redirect to another webpage in JavaScript/jQuery?

相关问题