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

Posted

技术标签:

【中文标题】销毁地图实例的正确方法是啥?【英文标题】:What is the Proper Way to Destroy a Map Instance?销毁地图实例的正确方法是什么? 【发布时间】:2012-05-16 04:01:16 【问题描述】:

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

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

【问题讨论】:

相关问题(2014):***.com/questions/21142483/… 尝试删除地图上所有事件监听器的代码,谷歌地图错误35821412 【参考方案1】:

我在这个问题上添加了第二个答案,因为我不想删除我们通过后续 cmets 对我之前的答案的来回。

但我最近发现了一些直接解决您的问题的信息,所以我想分享一下。我不知道您是否知道这一点,但在 Google Maps API Office Hours May 9 2012 Video 期间,来自 Google 的 Chris Broadfoot 和 Luke Mahe 讨论了来自 *** 的这个问题。如果您将视频播放设置为 12:50,那是他们讨论您问题的部分。

基本上,他们承认这是一个错误,但也补充说他们并不真正支持涉及创建/销毁连续地图实例的用例。他们强烈建议创建地图的单个实例并在任何此类场景中重用它。他们还谈到将地图设置为 null,并明确删除事件侦听器。您表达了对事件监听器的担忧,我认为只需将地图设置为 null 就足够了,但看起来您的担忧是有效的,因为它们特别提到了事件监听器。他们还建议完全删除包含地图的 DIV。

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

【讨论】:

谢谢 - 我让他们在办公时间解决这个问题,但还没有机会查看视频。 嗯,你可以简单地更新之前的答案,提到它是一个更新...... 太棒了..现在是 2018 年,似乎仍然没有办法做到这一点。【参考方案2】:

official answer 是你不知道的。单页应用程序中的地图实例应该被重用,而不是被销毁然后重新创建。

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

【讨论】:

这非常非常糟糕——我有多语言单页应用程序,我想在选定的语言上显示谷歌地图。 这个好像是fixed as of version 3.38.1(虽然我还没有独立验证过)。【参考方案3】:

显然你不能真正销毁地图实例,如果

您需要在网站上同时显示多张地图 地图数量可能会随着用户交互而变化 地图需要隐藏并与其他组件一起重新显示(即它们不会出现在 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 相关的函数)和container ,您可以使用“myDivClassHereForStyling”类对其进行样式设置,并且可以动态地附加到 DOM。 如果需要重置系统,可以使用 mapInstancesPool.reset()。它将计数器重置为 0,同时将所有现有实例保留在池中以供重用。 在我的应用程序中,我需要一次删除所有地图并创建一组新地图,因此没有回收特定地图实例的功能:您的里程可能会有所不同。 为了从屏幕上移除地图,我使用了 jQuery 的 detach,它不会破坏地图的容器。

通过使用这个系统,并使用

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

正在运行

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

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

【讨论】:

【参考方案4】:

我会建议删除地图 div 的内容并在保存对地图的引用的变量上使用 delete,并可能明确地 deleteing 任何事件侦听器。

虽然有an acknowledged bug,但这可能不起作用。

【讨论】:

这是一个很好的讨论。我不认为打电话给delete 增加了很多(见***.com/q/742623/1314132),但它真的不会受到伤害。最后,归结为这个问题:是否有对对象的引用?如果是,则不会被垃圾回收。 @SeanMickey:这就是错误变得相关的地方。版本 2 有 GUnload() 删除所有 API 的内部引用。 我一直在 Chrome 中测试这个页面:people.missouristate.edu/chadkillingsworth/mapsexamples/… 到目前为止,地图移除后的内存使用量仅略有下降,但远不及地图实例化之前的水平。跨度> @AndrewLeach 绝对是。但是,如果他们有一个导致内存泄漏的错误,那么在修复之前我们无能为力。我的意思是,如果无法使所有地图对象都无法访问,那么delete 并不是真正的解决方案。他们必须修复大问题,以便使引用无法访问,或者添加一个新函数来提供您为GUnload() 描述的功能。 Chad/Andrew:是的,我已经重现了这个问题,不幸的是delete 并清除innerHTML 并不能完全清除内存。不幸的是,这不是一个高优先级的错误。【参考方案5】:

由于 google 没有为 api v3 提供 gunload(),因此最好在 html 中使用 iframe 并将 map.html 作为该 iframe 的源。使用后将 src 设为 null。这肯定会释放 map 消耗的内存。

【讨论】:

每个 iframe 实例都必须重新加载不理想的地图 api。【参考方案6】:

当您移除div 时,即移除显示面板并且地图将消失。要删除地图实例,只需确保您对地图的引用设置为null,并且对地图其他部分的任何引用设置为null。届时,javascript 垃圾收集将负责清理,如:How does garbage collection work in JavaScript? 中所述。

【讨论】:

我不确定将 map 变量设置为 null 是否会正确删除所有事件侦听器。 不仅地图必须设置为null,还包括对其他任何内容的任何引用。因此,如果标记引用设置为null,使其无法访问,则无法访问事件侦听器。它可能仍然连接到地图,但无法到达地图,所以它只是一大块内存,基本上已经成为孤儿。与设置Array.length = 0 相同;如果没有其他对成员的引用,它们只会形成一组有资格进行垃圾回收的孤立内存。【参考方案7】:

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

它会在可以使用removeEventListener 时删除事件。这意味着它会使用它在此元素上添加的事件侦听器来保存一个数组。 当 addEventListener 不可用时,它使用 DOM 元素上的 delete 删除有关事件的属性(onclickonblur 等)(仍然有一个数组来存储添加的事件)。 它将元素设置为 null 以避免 IE 6/7/8 内存泄漏。 然后删除元素。

【讨论】:

我主要指的是内部的 Google Maps API 事件。可以使用developers.google.com/maps/documentation/javascript/… 中记录的 API 事件方法添加/删除/触发它们。虽然在功能上与浏览器 addEventListener 类似,但有大量特定于地图的自定义事件(例如“bounds_changed”,其中一些事件处理程序会挂钩到浏览器事件,例如地图“resize”事件。 然后根据事件类型使用removeEventListenerdelete 手动添加和删除事件数组。

以上是关于销毁地图实例的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Angular如何正确销毁指令

销毁锁定的互斥锁时 pthread_mutex_destroy 的正确行为是啥

如何正确销毁 CKEditor 实例?

JavaScript:通过类方法创建和销毁类实例

@Bean 指定初始化和销毁方法

EffectiveJava——第二章 创建和销毁对象