【问题标题】:Javascript Memory Leak with Google Maps' Map.panTo() MethodJavascript 内存泄漏与谷歌地图的 Map.panTo() 方法
【发布时间】:2011-11-18 18:49:25
【问题描述】:

我在加载 Google 地图并不断从一个点平移到另一个点的 Web 应用程序时遇到 Javascript Out of Memory 错误。它需要大约半天的时间才能耗尽内存,但我真的希望它持续更长时间。一世 已经确定在使用 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. 赏金将颁发给想出如何修复内存泄漏的人或明确识别并证明无法修复的原因(如果是这样的话)的人。

代码:

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

【问题讨论】:

  • 您正在下载多少兆字节的图像?
  • 有点难以证明是否定的(泄漏“无法修复”):-) 我已提交给 Google 论坛,请参阅下面的更新答案。

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


【解决方案1】:

为什么要为地图创建哈希表?您可以将地图创建为全局变量。我会很惊讶这有什么不同,但是你的评论“//已经尝试了 HashTable 和 Array (Both Leak)...”让我想知道为什么你需要一个 hashtable 或一个数组。

你也可以去掉 objMapOptions 和 objMapCenterPoint 变量,只需将选项结构直接传递给 Map() 函数,同样将 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 用于静态地图 API 和缓存建议。我希望它不会到那个地步(我们设置了标记,整个项目比仅仅在两点之间切换更健壮和动态)。删除哈希表没有任何区别(我从使用的多个地图中提取的原始项目,因此哈希表使代码更简洁)。
【解决方案2】:

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

【讨论】:

  • 我应该提出我已经尝试过这个建议的问题。我会编辑。
【解决方案3】:

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

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

建议:

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

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

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

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

3) 请务必查看不同的浏览器对您的问题的影响是否不同。 ESP 试试谷歌浏览器。

已添加

我重新编写了您的演示代码以将 LatLng 调用移出循环,但它仍然泄漏。另外,最好在setTimeout 调用中使用非字符串值,所以我也更改了它。我还使用Maps API tutorial 将文档类型设置为他们推荐的内容。

结果如下。它在 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>

【讨论】:

【解决方案4】:

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

How to redirect to another webpage in JavaScript/jQuery?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-05
    • 2013-09-12
    • 2012-06-20
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 2011-02-28
    相关资源
    最近更新 更多