BingMap频繁Add Pushpin和Delete Pushpin会导致内存泄露

最近在做性能测试的时候发现BingMap内存泄露(memory leak)的问题,查找了一些国外的帖子,发现也有类似的问题,但是没有好的解决办法。

https://social.msdn.microsoft.com/Forums/en-US/3226f255-2ae1-4718-b848-5f24e76b64b0/your-pushpins-are-broken-addremove-leads-to-memory-leak?forum=bingmapsajax

经过一番尝试,找到了一个折中的解决方案,分享一下。

先贴一下Testing Code吧:

<!DOCTYPE html>
<%--<meta http-equiv='x-ua-compatible' content='IE=7;IE=9' />--%>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
	<script src="Scripts/jquery-1.8.3.min.js" type="text/javascript"></script>
	<script charset="UTF-8" type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
</head>
<body>
    <form id="form1" runat="server">
    <div id="myMap" style="width:800px;height:600px;position:absolute">
	</div>
	<input id="btnAdd" type="button" style="position:absolute;top:700px;left:10px;" value="Add" onclick="addBatchPushpin();"/>
	<input id="btnDelete" type="button" style="position:absolute;top:700px;left:110px;" value="Delete" onclick="deleteBatchPushpin();" />
	<input id="btnClear" type="button" style="position:absolute;top:700px;left:210px;" value="Clear" onclick="clearPushpin();"/>
	<input id="Button1" type="button" style="position:absolute;top:700px;left:310px;" value="Find" onclick="findPushpin();"/>

	<div id="hidElement"></div>
    </form>
</body>
</html>
<script type="text/javascript" >
	var map = null;
	var _layer = null;
	var _bingMapKey = "ApirbCqPCAM1bVBVeh5CrrNm-7lzdCkbDT5OPkck8pXXeKWWGNUrIGsTqlkDHlu8";
	$(document).ready(function ()
	{
		var mapOptions = {
			credentials: _bingMapKey,
			enableClickableLogo: false,
			enableSearchLogo: false,
			showMapTypeSelector: true,
			showCopyright: false
		}
		map = new Microsoft.Maps.Map($("#myMap")[0], mapOptions);
		var infoboxLayer = new Microsoft.Maps.EntityCollection();
		map.entities.push(infoboxLayer);
		map.setView({ animate: true, zoom: 5, center: new Microsoft.Maps.Location(40, -71) });

		_layer = new Microsoft.Maps.EntityCollection();
		map.entities.push(_layer);

		//var lat = 40.56090348161442;
		//var lon = -74.345836486816438;
		//addPushpin(lat,lon);

		setInterval(addBatchPushpin, 500);
		setInterval(deleteBatchPushpin, 1000);
	})

	function addBatchPushpin()
	{
		var lat = 40.56090348161442;
		var lon = -74.345836486816438;
		for (var i = 0; i < 20; i++)
		{
			var randomLatitude = Math.random() + lat;
			var randomLongitude = Math.random() + lon;

			addPushpin(randomLatitude, randomLongitude);
		}
	}

	function deleteBatchPushpin()
	{
		var len = _layer.getLength();
		for (var i = 0; i < len; i++)
		{
			_layer.removeAt(0);
			$('#cfsNew').remove();
			window.CollectGarbage();
		}
	}

	function addPushpin(lat, lon)
	{
		var htmlTest = '<table id="cfsNew" cellpadding="0" cellspacing="0"><tr><td><div style="border: black 2px solid; padding-bottom: 0em; line-height: 12px; background-color: white; margin: 0em;padding-left: 0px; padding-right: 0px; font-family: Arial; color: black;font-size: 12px; font-weight: bold;padding-top: 0em;"><div style="white-space: nowrap;">{P2012-001093} </div><div style="font-weight: bold; font-size: 12px; font-family:Arial"><table style="font-size:inherit;" cellpadding="0" cellspacing="0"><tr><td style="width: 5px; height:5px;"><div style=" background-color: rgb(0,128,0); width: 5px;display: block; margin-bottom: 2px; height: 6px; overflow: hidden; margin-right: 1px"> </div></td><td style="color: rgb(0,128,0);font-size: 12px; font-family:Arial; font-weight:bold;">{297}</td></tr><tr><td style="width: 5px;"><div style=" background-color: rgb(0,128,0); width: 5px;display: block; margin-bottom: 2px; height: 6px; overflow: hidden; margin-right: 1px"></div></td><td style="color: rgb(0,128,0);font-size: 12px; font-family:Arial; font-weight:bold;">907</td></tr><tr><td style="width: 5px;"><div style=" background-color: rgb(255,0,0); width: 5px;display: block; margin-bottom: 4px; height: 6px; overflow: hidden; margin-right: 1px"></div></td><td style="color: rgb(0,128,0);font-size: 12px; font-family:Arial; font-weight:bold;">401</td></tr><tr><td style="width: 5px;"><div style=" background-color: rgb(0,0,220); width: 5px;display: block; margin-bottom: 4px; height: 6px; overflow: hidden; margin-right: 1px"></div></td><td style="color: rgb(0,128,0);font-size: 12px; font-family:Arial; font-weight:bold;">408</td></tr></table></div></div></td></tr><tr><td align="center"><div align="center"><img style="position:relative; width: 40px; height: 40px; left: 20px;top:-1px;" src="Images/ReOpened Box.png" />                    <img style="position:relative; width: 35px; height: 35px; left: -21px; top: -1px;" src="Images/pin.png" /></div></td></tr></table>';
		var loc = new Microsoft.Maps.Location(lat, lon);
		var html = htmlTest;

		var pushpinOptions = { htmlContent: html, zIndex: 100000, width: getWidth(html) };
		var pushpin = new Microsoft.Maps.Pushpin(loc, pushpinOptions);
		_layer.push(pushpin);
	}

	function clearPushpin()
	{
		_layer.clear();
		window.CollectGarbage();
	}

	function findPushpin()
	{
		var test = $('#cfsNew').length;
		alert(test);
	}

	function getWidth(html)
	{
		element = $("#hidElement");
		element.html(html);
		var height = element[0].scrollHeight;
		var width = element.children().width();
		return width;
	}

</script>

分析一下具体的原因吧,就是往地图上增加pushpin的时候,实际上是增加了一个HTML元素,但是移除的时候只是调用_layre.remove(pushpin)或者_layer.removeAt(index),这两个方法是一样的效果,只是从BingMap的EntityCollection集合中移除了Pushpin对象,但是Pushpin的HTML对象在内存中依然存在,所以频繁增加移除会导致内存不断的增长。

测试结果:

1. 将cfsNew的HTML元素直接放到页面上,然后每次通过取DOM元素的方式取去添加到地图上,内存增长的速度大概是每秒10M。

2. 将cfsNew的HTML写成一个var的字符串的形式赋给Pushpin的contentHTML上,内存增长的速度大概每秒1M。

3. 如果不用HTML格式的Pushpin,用默认的Pushpin的图标(水滴状),内存增加的频率为每秒0.1M。

4. 添加了$(‘#cfsNew‘).remove();方法之后,内存持续增加的情况消失了。

目前我只是通过删除是手动移除HTML对象的方式解决这个问题,不过由于每个图标的HTML是不一样的,还需要绑定特别的属性做这样的标记,给程序开发增加了很大的不方便,还是希望Microsoft能发现并解决这个问题。

时间: 2024-10-09 20:58:16

BingMap频繁Add Pushpin和Delete Pushpin会导致内存泄露的相关文章

BingMap改变鼠标样式【Map/Pushpin/Polygon】

<span style="font-size:18px;">Microsoft.Maps.Events.addHandler(map, "mousemove", function (e) { // get the HTML DOM Element that represents the Map var mapElem = map.getRootElement(); if (e.targetType === "map") { // Mo

C++: delete与内存泄露

在C++中可以方便地通过运算符new和delete来动态分配内存,其中new的默认语义是分配内存并调用构造函数,而delete的默认语义是调用析构函数并释放内存,需要注意的是这两个运算符都和指针打交道,而涉及到指针事情就有点复杂了,来看一个例子: class A { public: ~A() { cout<<"destructor of A"<<endl; } }; class B : public A { public: ~B() { cout<<

C++ Primer 学习笔记_29_操作符重载与转换(4)--转换构造函数和类型转换运算符归纳、operator new 和 operator delete 实现一个简单内存泄漏跟踪器

C++ Primer 学习笔记_29_操作符重载与转换(4)--转换构造函数和类型转换运算符归纳.operator new 和 operator delete 实现一个简单内存泄漏跟踪器 一.转换构造函数 可以用单个实参来调用的构造函数定义从形参类型到该类型的一个隐式转换.如下: class Integral { public: Integral (int = 0); //转换构造函数 private: int real; }; Integral A = 1; //调用转换构造函数将1转换为In

【ThinkingInC++】64、重载new和delete,来模仿内存的分配

/** * 书本:[ThinkingInC++] * 功能:重载new和delete,来模仿内存的分配 * 时间:2014年10月5日14:30:11 * 作者:cutter_point */ #include <cstddef> //size_t这个类型的使用 #include <fstream> #include <iostream> #include <new> using namespace std; ofstream out("Frami

Qt中内存泄露和退出崩溃的问题 delete

Qt中帮程序员做了一些内存回收的事情,但正因为这些反而让对此不熟悉的人会屡屡犯错. 收录一篇不错的文章: 在C++中学习过程中,我们都知道: delete 和 new 必须 配对使用(一 一对应):delete少了,则内存泄露,多了麻烦更大. Qt作为C++的库,显然是不会违背C++的前述原则的.可是: 在Qt中,我们很多时候都疯狂地用new,却很少用delete,缺少的 delete 去哪儿了?! 注:本文暂不涉及智能指针(smart pointer)相关的东西,你可以考虑 Qt 智能指针学习

new delete 直接管理的内存的规则

primer 5th 12.6练习代码 #include <iostream> #include <algorithm> #include<memory> #include<vector> using std::vector; using std::cin; using std::cout; using std::endl; vector<int>* factory(int i) { ; return new vector<int>{

C++ delete掉的是new出的堆区内存,无法delete掉栈区的内存

直接上代码感受一下: #include <iostream>using namespace std; int main(){ int a=3; int* p1=&a; int* p2=new int(8); cout<<a<<' '<<*p1<<' '<<p1<<' '<<*p2<<' '<<p2<<endl; delete p1; delete p2; cout&l

Item 52:写了placement new就要写placement delete

Item 52: Write placement delete if you write placement new "placement new"通常是专指指定了位置的new(std::size_t size, void *mem),用于vector申请capacity剩余的可用内存. 但广义的"placement new"指的是拥有额外参数的operator new. new和delete是要成对的,因为当构造函数抛出异常时用户无法得到对象指针,因而delete

Effective C++学习进阶版

记得前段时间又一次拿起<Effective C++>的时候,有种豁然开朗的感觉,所以翻出了我第一遍读时做的笔记.只做参考以及查阅之用.如有需要请参阅<Effective C++>书本. by shenzi/2010.5.17 一.让自己习惯C++    条款01:视C++为一个语言联邦    为了更好的理解C++,我们将C++分解为四个主要次语言: C.说到底C++仍是以C为基础.区块,语句,预处理器,内置数据类型,数组,指针统统来自C. Object-Oreinted C++.这