Google 地图的 Javascript 内存泄漏 Map.panTo()方法

发布于 2024-12-05 08:46:06 字数 2880 浏览 0 评论 0原文

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

编辑:

  1. 我尝试过使用不同版本的 Google Maps API(2、3.0 和 3.6)。
  2. 我知道我不需要将示例代码中的映射放入哈希表或数组中,但这无论如何不会影响内存泄漏。
  3. 我试图避免黑客攻击,例如经常刷新页面或使用静态 Google 地图 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>

I have been experiencing Javascript Out of Memory errors with a Web App that loads a Google Map and continuously pans from one point to the other. It takes about a half day before it runs out of memory, but I would really like it to last far longer. I
have identified that the memory leak occurs when the map.panTo method is used, although
I very much suspect that it could be the way I'm using it (Javascript is not my strong
suit). Can you please look at this code and help me fix this memory leak? I have sped up the interval that it pans in this demo code for sake of time during debugging (the leak is obvious even by checking the process in Windows Task Manager). This runs off of ASP .Net 3.5 Web Forms, but there are no PostBacks and the code is completely HTML, CSS, and Javascript. It leaks the worst in IE (which is what I need to use to display this).

Edit:

  1. I have tried using different versions of the Google Maps API (2, 3.0, and 3.6).
  2. I know that I don't need to put the map in the example code into a Hashtable or Array, but that doesn't affect the memory leak anyways.
  3. I'm trying to avoid a hack, such as refreshing the page every so often or using the static Google Maps API.
  4. Bounty will go to whoever figures out how to fix the memory leak or whoever clearly identifies and proves why it can't be fixed (if that is the case).

Code:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

半步萧音过轻尘 2024-12-12 08:46:06

为什么要为地图创建哈希表?您可以将地图创建为全局变量。我很惊讶这会产生任何影响,但你的评论“//已经尝试过哈希表和数组(两者都泄漏)......”让我想知道为什么你需要哈希表或数组。

您还可以通过将选项结构直接传递到 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来旋转地图吗?图像?

Why do you create a hashtable for the map? You could just create your map as a global variable instead. I'd be surprised that makes any difference, but your comment that "//Have tried both HashTable and Array (Both Leak)..." makes me wonder why you need either a hashtable or an array.

You could also get rid of the objMapOptions and objMapCenterPoint variables by just passing the structure of options directly into the Map() function, and likewise with the latLng into the panTo() functions.

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

Another suggestion, what about caching the maps? I don't know if this sample code is actually what you're doing, but if it's just flitting between two maps in this manner, couldn't you use the static map api, and cache the images and just use javascript to rotate the images?

迷离° 2024-12-12 08:46:06

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

Just had another thought. You're specifying v=2, i.e. getting the version 2 release of this API. The current version is 3.6. Suggest you try updating the version number (or just remove the v parameter to get the latest stable version) and see if that improves things. Possibly they've tidied up any garbage collection in more recent versions.

唯憾梦倾城 2024-12-12 08:46:06

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

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

建议:

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

2) 考虑一下总体问题——您试图连续平移 Google 地图 6 小时或更长时间。您为什么认为泄漏发生在您的代码中?问题更有可能出在 G 地图上。下载的地图图像图块可能保存在本地,因为用户可能想要向后平移。

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

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

3)一定要看看不同的浏览器是否对您的问题产生不同的影响。特别是尝试谷歌浏览器。

已添加

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

结果如下。它在 FF 和 Chrome 上泄漏。我在 Google Maps API v3 论坛 上提交了一篇帖子。

显然 .panTo 方法存在泄漏。我想您的下一步是查看 Google 员工是否回复该帖子。

测试用例演示

重新设计的测试用例:

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

Looks like you're only storing one element in the "Hashtable" Object--["ShiftingMap"] -- it is not holding maps, it is holding the one map. You could just use a global variable to hold the map object.

The only repeating allocation is the new google.maps.LatLng(decLat, decLng) which is created for every pan.

Suggestions:

1) The docs for LatLng don't give any warnings about needing to explicitly free the objects, so presumably the garbage collector should handle it.

2) Think about the overall problem--you're trying to continuously pan a Google map for 6 hours or more. Why do you think the leak is in your code? It's more likely that the problem is in G Maps. Probably the downloaded map image tiles are kept locally since it would be likely that the user would want to pan back.

As a test, try panning just back and forth between two points, rather than the current panning across the globe. (If I'm understanding your relative shifting correctly.)

See if the leak happens at the rate of memory / hour

3) Be sure to see if different browsers affect your problem differently. Esp try Google Chrome.

Added

I re-worked your demo code to move the LatLng call out of the loop and it still leaks. Also, it is best to use a non-string value in setTimeout calls, so I changed that too. I also used the Maps API tutorial to set the doctype to what they recommend.

Result is below. It leaks on FF and Chrome. I filed a post at the official Google Maps API v3 forum.

It seems clear that the .panTo method leaks. I guess your next step is to see if a Googler responds to the post.

Test case demo

Reworked test case:

<!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>
单调的奢华 2024-12-12 08:46:06

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

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

You can try refreshing the page once you have looped through your data using JavaScript. That might free the memory being used by the script running on the page:

How to redirect to another webpage in JavaScript/jQuery?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文