销毁地图实例的正确方法是什么?


89

我最近开发了html5移动应用程序。该应用程序是一个页面,其中导航哈希更改事件替换了整个DOM。该应用程序的一部分是使用API​​ v3的Google Map。在从DOM中删除map div之前,我想删除所有事件处理程序/侦听器并释放尽可能多的内存,因为用户可能不会再次返回该部分。

销毁地图实例的最佳方法是什么?



尝试删除地图上所有事件监听器的代码,Google Maps Bug 35821412
kashiraja

Answers:


48

我要在这个问题上添加第二个答案,因为我不想通过对先前答案的后续评论来回删除。

但是我最近遇到了一些直接解决您问题的信息,因此我想分享一下。我不知道您是否知道这一点,但是在Google Maps API办公时间2012年5月9日视频中,来自Google的Chris Broadfoot和Luke Mahe从stackoverflow讨论了这个问题。如果将视频播放设置为12:50,则这是他们讨论问题的部分。

从本质上讲,他们承认这是一个错误,但同时补充说,他们并不真正支持涉及创建/销毁连续地图实例的用例。他们强烈建议创建单个地图实例,并在任何这种情况下重新使用它。他们还讨论将地图设置为null,并显式删除事件侦听器。您表达了对事件侦听器的担忧,我认为仅将map设置为null就足够了,但是看起来您的担忧是有效的,因为它们特别提到了事件侦听器。他们还建议完全删除保存地图的DIV。

无论如何,只是想将其传递并确保它已包含在stackoverflow讨论中,并希望它对您和其他人有帮助-


2
谢谢-我要求他们在办公时间解决问题,但还没有机会查看视频。
乍得·基林斯沃思

好吧,您可以简单地更新以前的答案,并说这是一个更新...
TJ

4
太棒了..这是2018年,似乎仍然没有办法做到这一点。
JP Silvashy

28

官方的回答是你不知道。单页应用程序中的地图实例应被重用,并且不被销毁然后重新创建。

对于某些单页应用程序,这可能意味着重新架构解决方案,以便一旦创建地图,就可以将其隐藏或与DOM断开连接,但永远不要销毁/重新创建它。


这非常非常糟糕-我有多语言单页应用程序,我想以选定的语言显示Google Map。
artuska '18

14

由于显然您无法真正销毁地图实例,因此可以通过以下方法减少此问题:

  • 您需要一次在网站上显示几张地图
  • 地图的数量可能会随着用户互动而改变
  • 需要隐藏地图并将其与其他组件一起重新显示(即,它们不会出现在DOM中的固定位置)

正在保留地图实例池。该池会跟踪正在使用的实例,并在请求一个新实例时检查是否有可用的地图实例是空闲的:如果存在,它将返回一个现有的地图实例;如果不是,它将创建一个实例。新的地图实例并将其返回,并将其添加到池中。这样,您最多只能拥有与您在屏幕上同时显示的最大地图数量相等的实例。我正在使用此代码(它需要jQuery):

var mapInstancesPool = {
 pool: [],
 used: 0,
 getInstance: function(options){
    if(mapInstancesPool.used >= mapInstancesPool.pool.length){
        mapInstancesPool.used++;
        mapInstancesPool.pool.push (mapInstancesPool.createNewInstance(options));
    } else { 
        mapInstancesPool.used++;
    }
    return mapInstancesPool.pool[mapInstancesPool.used-1];
 },
 reset: function(){
    mapInstancesPool.used = 0;
 },
 createNewInstance: function(options){
    var div = $("<div></div>").addClass("myDivClassHereForStyling");
    var map =   new google.maps.Map(div[0], options);
    return {
        map: map,
        div: div
    }
 }
}

您向其传递起始地图选项(根据google.maps.Map的构造函数的第二个参数),它返回地图实例(您可以在其上调用与google.maps.Map有关的函数)和容器(您可以使用“ myDivClassHereForStyling”类设置样式,并且可以动态地附加到DOM。如果需要重置系统,则可以使用mapInstancesPool.reset()。它将计数器重置为0,同时保留池中所有现有实例以供重用。在我的应用程序中,我需要立即删除所有地图并创建一组新地图,因此没有回收特定地图实例的功能:您的行驶里程可能会有所不同。为了从屏幕上删除地图,我使用jQuery的detach,它不会破坏地图的container。

通过使用该系统,并使用

google.maps.event.clearInstanceListeners(window);
google.maps.event.clearInstanceListeners(document);

并运行

google.maps.event.clearInstanceListeners(divReference[0]);
divReference.detach()

(其中divReference是从实例池返回的div的jQuery对象)在我要删除的每个div上,我设法使Chrome的内存使用或多或少保持稳定,而不是每次删除地图和添加新地图时都会增加。


您挽救了我的生命!Thnks;)
Felipe Desiderati

很高兴有帮助!!
Paolo Mioni

5

我本来建议删除map div的内容,并delete在持有对地图的引用的变量上使用,并且可能显式地delete调用任何事件侦听器。

但是,存在一个已确认的错误,这可能无法正常工作。


这是一个很好的讨论。我认为调用不会delete增加太多(请参阅stackoverflow.com/q/742623/1314132),但这确实不会造成伤害。最后,归结为这个问题:是否有对该对象的引用?如果是,则不会进行垃圾收集。
肖恩·米奇

1
@SeanMickey:该错误与之相关。版本2必须GUnload()删除所有API的内部引用。
安德鲁·里奇

我已经在Chrome中测试此页面:people.missouristate.edu/chadkillingsworth/mapsexamples / ...到目前为止,删除地图后的内存使用量仅略有下降,但与实例化地图之前的水平相差甚远。
乍得·基灵斯沃思

@AndrewLeach绝对。但是,如果他们有一个导致内存泄漏的错误,那么在修复该错误之前,我们无能为力。我的意思是,如果使所有地图对象都无法访问不起作用,那么delete这实际上不是解决方法。他们必须解决一些大问题,以使引用无法正常工作,或者添加一个新功能来提供您描述的功能GUnload()
肖恩·米奇

1
Chad / Andrew:是的,很遗憾,我已经重现了此问题,delete并且清除innerHTML内存并不能完全清除内存。不幸的是,这不是一个高优先级的错误。
克里斯·布罗德富特

2

由于google不为api v3提供gunload(),因此最好在html中使用iframe并将map.html分配为该iframe的源。使用后,使src为null。那肯定会释放地图消耗的内存。


2
然后,iframe的每个实例都必须重新加载不理想的maps api。
乍得·基林斯沃思2013年

1

删除时div,将删除显示面板,地图将消失。要删除地图实例,只需确保将对地图的引用设置为,null并将对地图其他部分的所有引用设置为null。届时,JavaScript垃圾收集将负责清理工作,如以下内容所述:垃圾收集如何在JavaScript中工作?


1
我不确定将map变量设置为null是否会正确删除所有事件侦听器。
乍得·基灵斯沃思

1
不仅必须将地图设置为null,还应引用其他任何内容。因此,如果标记引用设置为null,使其无法访问,则无法访问事件侦听器。它可能仍然连接到地图,但是无法访问地图,因此实际上只是孤立的一个大块内存。与设置Array.length = 0; 如果没有其他对成员的引用,则它们仅构成一组可以进行垃圾回收的孤立内存。
肖恩·米奇

0

我猜你在说什么addEventListener。当您删除DOM元素时,某些浏览器会泄漏这些事件,而不会将其删除。这就是为什么jQuery在删除元素时会做几件事的原因:

  • 可以使用时删除事件removeEventListener。这意味着它将与添加到此元素的事件侦听器保持数组。
  • 当DOM元素不可用时onclick,它将删除事件(,onblur等)的属性(仍然有一个数组,用于存储添加的事件)。deleteaddEventListener
  • 它将元素设置null为避免IE 6/7/8内存泄漏。
  • 然后将其删除。

我主要是指内部Google Maps API事件。可以使用developer.google.com/maps/documentation/javascript/…中记录的API事件方法添加/删除/触发它们。尽管在功能上与浏览器的addEventListener类似,但是有大量特定于地图的自定义事件(例如“ bounds_changed”,并且其中一些事件处理程序也与浏览器事件挂钩,例如地图“ resize”事件。)
Chad Killingsworth

然后保留添加的事件数组,然后使用removeEventListenerdelete根据事件类型手动删除。
Florian Margaine
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.