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能發現並解決問題。
BingMap頻繁Add Pushpin和Delete Pushpin會導致內存泄露