闭包 内存泄漏

Sunday0508 2018-12-13 05:29:50
在MFC程序中,使用web Browser控件显示百度地图,标注并刷新显示多个设备的实时位置等信息。目前功能都能正常实现,就是程序运行一段时间过后占用的内存明显增加。

最终把范围确定到JS中的ShowMarkers()函数。每秒刷新站点信息的时候会调用一次此函数。

把ShowMarkers()函数中for循环中的代码注释掉以后,程序占用内存稳定不增长。
把ShowMarkers()函数中闭包内的代码注释掉,只留下闭包的框架以后,程序占用内存依然泄漏。
确定是闭包导致的内存。我觉得就是因为作用域链,闭包保存了ShowMarkers()函数里面的几个局部数组的引用,导致局部数组不能释放。

请各位帮帮看看为什么闭包里面完全不引用任何外部函数的变量,是怎么泄漏内存的,该如何修改可以保证不泄漏内存。

为了方便聚焦具体问题,我把代码抽象了一下。

//外部若干全局数组,下面为例子,只是为了说明有多个全局的数组,数组元素个数也不一定是100
var g_arr1=new array(100);
var g_arr2=new array(100);
var g_arrn=new array(100);

function ShowMarkers(bClearMarkers) {

var typeArray = new Array(100);
var nameArray = new Array(100);
var infoArray = new Array(100);
var brngArray = new Array(100);

var points = [];//将大数组分成小数组存放。
for (; i < 5; i++) {
points[i] = [];
points[i].push(1); points[i].push(2); points[i].push(3); points[i].push(n);//只是说明里面保存了多个坐标点
}

var ajaxLen = points.length;
//闭包和回调。
for (; j < ajaxLen; j++) {
(function () {
var jj = j;
//回调函数,添加marker。
var callback = function (data) {//data是经过转换后的坐标数组
//具体的显示/刷新设备位置信息代码,此处省略。因为注释掉一样泄漏内存
callback = null;//清理内存。
data = null;
jj = null;
}
convertor.translate(points[j], 1, 5, callback);//坐标转换新的数据图标添加到地图上。此函数为异步函数,需要等待百度服务器返回转换过后的坐标
})();
}
}


真实代码

//几个全局数组,保存最新的站点信息
var pointsArrayMarker = new Array();
var nameArrayMarker = new Array();
var typeArrayMarker = new Array();
var infoArrayMarker = new Array();
var brngArrayMarker = new Array();
var ArrayMarker = new Array();

function ShowMarkers(bClearMarkers) {
if (bClearMarkers == "1")
{
DeleteMarkers();
}

var typeArray = new Array();
for (var i = 0; i < typeArrayMarker.length; i++) {
if (refreshArrayMarker[i] == '0')
continue;
typeArray.push(typeArrayMarker[i]);
}
var nameArray = new Array();
for (var i = 0; i < nameArrayMarker.length; i++) {
if (refreshArrayMarker[i] == '0')
continue;
nameArray.push(nameArrayMarker[i]);
}
var infoArray = new Array();
for (var i = 0; i < infoArrayMarker.length; i++) {
if (refreshArrayMarker[i] == '0')
continue;
infoArray.push(infoArrayMarker[i]);
}
var brngArray = new Array();
for (var i = 0; i < brngArrayMarker.length; i++) {
if (refreshArrayMarker[i] == '0')
continue;
brngArray.push(brngArrayMarker[i]);
}

var len = pointsArrayMarker.length;
var points = [];//将大数组分成小数组存放。
var ajaxId = 0;//第几组请求
var i = 0;
var j = 0;
var ajaxLen = 0;//要发起几次请求。
var gap = 10;
var iCountRefresh = 0;
//数组分装
for (; i < len; i++) {
if (refreshArrayMarker[i] == '0') {
continue;
}

if (iCountRefresh % gap == 0) {
ajaxId = Math.floor(iCountRefresh / gap);
points[ajaxId] = [];
}
iCountRefresh++;
points[ajaxId].push(pointsArrayMarker[i]);
}

ajaxLen = points.length;
//闭包和回调。
for (; j < ajaxLen; j++) {
(function () {
//var jj = j; //闭包特点:内部函数可以访问外部函数变量
//回调函数,添加marker。
var callback = function (data) {
var ajaxId = jj;
//var len = pointsArrayMarker.length, i;
var len = typeArray.length, i;
var base = ajaxId * gap; //本数组在原始大数组中的起始位。
if (data.status === 0) {
var dateLen = data.points.length;
for (i = 0; i < dateLen; i++) {
if (bClearMarkers == "1")
{
var marker = new BMap.Marker(data.points[i]);
if (typeArray[base + i] == '1') {
marker.setIcon(iconGreen);
marker.setRotation(brngArray[base + i]);
marker.setShadow(iconGreen);
}
else if (typeArray[base + i] == '0') {
marker.setIcon(iconGrey);
marker.setRotation(brngArray[base + i]);
marker.setShadow(iconGrey);
}
map.addOverlay(marker);

var label = new BMap.Label(nameArray[base + i], { offset: new BMap.Size(20, -5) });
marker.setLabel(label);

ArrayMarker.push(marker);

var sContent = GetStringHtmlInfoWindow(nameArray[base + i], infoArray[base + i]);
AddInfoWindow(marker, sContent);

if ((bShowMarkerInfoWindow == 1) && (nameMarkerInfowindow == nameArray[base + i])) {
marker.V.click();
}
}
else
{
var ii = 0;
for (ii = 0; ii < ArrayMarker.length; ii++)
{
if (ArrayMarker[ii].getLabel().content == nameArray[base + i])
break;
}
if (ii != ArrayMarker.length) {
ArrayMarker[ii].setPosition(data.points[i]);
if (typeArray[base + i] == '1') {
ArrayMarker[ii].setIcon(iconGreen);
ArrayMarker[ii].setRotation(brngArray[base + i]);
//ArrayMarker[ii].setShadow(iconGreen);
}
else if (typeArray[base + i] == '0') {
ArrayMarker[ii].setIcon(iconGrey);
ArrayMarker[ii].setRotation(brngArray[base + i]);
//marker.setShadow(iconGrey);
}
var sContent = GetStringHtmlInfoWindow(nameArray[base + i], infoArray[base + i]);
ArrayInfowindow[ii].setContent(sContent);
}

}
}
}
callback = null;//清理内存。
data = null;
jj = null;
}
convertor.translate(points[j], 1, 5, callback);//坐标转换新的数据图标添加到地图上。
})();
}
ClearMarkerArray();//清空最上面全局数组
}
...全文
334 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
Sunday0508 2018-12-18
  • 打赏
  • 举报
回复
百度地图那边确认是API的问题,目前没有很好的处理办法
Sunday0508 2018-12-14
  • 打赏
  • 举报
回复
引用 3 楼 讨厌走开啦 的回复:
看代码没看出什么问题,把调用ShowMarkers的频率降低一点,比如10秒调用一次看看问题还在不在,如果问题不在,可以怀疑是convertor.translate这里执行的时候是不是在排队,但是处理速度跟不上调用速度,导致队列越来越长。


现在看来可能是百度地图api在泄漏内存。


//省略载入百度地图相关代码
var points = new Array();
points.push(new BMap.Point(114.532752, 30.49466));
points.push(new BMap.Point(114.532652, 30.49466));
points.push(new BMap.Point(114.532552, 30.49466));
points.push(new BMap.Point(114.532452, 30.49466));
points.push(new BMap.Point(114.532352, 30.49466));

function ShowMarkers()
{
var callback = function (data) {
}
convertor.translate(points, 1, 5, callback);//坐标转换新的数据图标添加到地图上。
}
setInterval(ShowMarkers,200);

使用谷歌浏览器运行上述代码,内存都会持续增长

我先用谷歌浏览器看看是哪在漏内存
讨厌走开啦 2018-12-14
  • 打赏
  • 举报
回复
看代码没看出什么问题,把调用ShowMarkers的频率降低一点,比如10秒调用一次看看问题还在不在,如果问题不在,可以怀疑是convertor.translate这里执行的时候是不是在排队,但是处理速度跟不上调用速度,导致队列越来越长。
Sunday0508 2018-12-13
  • 打赏
  • 举报
回复
引用 1 楼 讨厌走开啦 的回复:
map.addOverlay(marker); 这里marker当你需要重新定位的时候要先调用removeOverlay方法移除,否则map对象里的marker就会越来越多,map对象越来越大,占用的内存自然越来越高。
现在是把闭包内所有地图操作的代码全都注释掉了,还是漏内存。 而且map.addOverlay(marker); 这个只是最开始显示的时候会会添加一次,后面都是用setPosition函数移动marker图标。 哎,谷歌地图也同样实现了全部同样的功能,是不泄露内存的。因为百度地图坐标转换必须异步,加入闭包以后就会泄露内存
讨厌走开啦 2018-12-13
  • 打赏
  • 举报
回复
map.addOverlay(marker); 这里marker当你需要重新定位的时候要先调用removeOverlay方法移除,否则map对象里的marker就会越来越多,map对象越来越大,占用的内存自然越来越高。

87,903

社区成员

发帖
与我相关
我的任务
社区描述
Web 开发 JavaScript
社区管理员
  • JavaScript
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧