高德地图API之内存泄漏

标签: 无 分类: 未分类 创建时间:2022-12-22 09:33:26 更新时间:2025-01-17 10:39:24

1.前言

我在使用高德地图api的时候,在火狐浏览器中,出现了内存泄漏的问题。可以看到这个火狐浏览器内存不断的在暴涨,我也面上什么都没有动,也还是在不断的暴涨。我排出了所有的vue的东西,最后只剩下了高德的代码,就会出现问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let geojson={ 
"type": "FeatureCollection",
"features": features
}
// 创建数据源
let dataSource = new Loca.GeoJSONSource({
data: geojson,
});

// 加载点图层、创建圆点图层
let pointLayer = new Loca.PointLayer({
zIndex: 10,
opacity: 1,
visible: true,
blend: 'lighter',
zooms: [2, 16],
});
// 图层添加数据
pointLayer.setSource(dataSource);


// 添加到地图上,问题就出在这个地方,当我把这段代码注释的时候,页面不会出现内存不断增长的问题,
// 但是我把这个代码打开,内存就会不断的飙升
loca.add(pointLayer);

还有一个奇怪的地方,就是说当我把页面最小化的时候,这个内存就不再增长了。另外就是同样的代码,在火狐下会出现问题,但是在谷歌下就不会出现这个问题。

理论上这是一个静态的图层,没有丝毫的动态内容,这应该不会出现问题,但是为什么出现了问题呢?要是我用官方的例子,添加 PointLayer 也不会出现问题。那会是哪里的问题呢?比如我使用官方的例子 无论在火狐还是谷歌,都不会出现内存泄漏的问题。

【解题思路】
(1) 排除可能的干扰选项,把全部的代码一步步的注释,直至出现问题的代码。
(2) 将全部的不确定要素进行排查,确保不要互相引用。

2.消除变量

这里我的唯一的一个变数就是这个 features 变量了。后来我尝试把这个features变量也消除,结果还是不行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
let geojson={ 
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": 65,
"properties": {
"X": 120.18798209978567,
"Y": 30.48288207977986,
},
"geometry": {
"type": "Point",
"coordinates": [
120.192597,
30.480531
]
}
},
{
"type": "Feature",
"id": 66,
"properties": {
"X": 120.19579890040778,
"Y": 30.482233229669298,
},
"geometry": {
"type": "Point",
"coordinates": [
120.200392,
30.479869
]
}
}
]
}
// 创建数据源
let dataSource = new Loca.GeoJSONSource({
data: geojson,
});

// 加载点图层、创建圆点图层
let pointLayer = new Loca.PointLayer({
zIndex: 10,
opacity: 1,
visible: true,
blend: 'lighter',
zooms: [2, 16],
});
// 图层添加数据
pointLayer.setSource(dataSource);


// 添加到地图上,问题就出在这个地方,当我把这段代码注释的时候,页面不会出现内存不断增长的问题,
// 但是我把这个代码打开,内存就会不断的飙升
loca.add(pointLayer);

3.loca动画影响

后来我写了一个demo,单独对这部分代码进行测试,结果显示并不会出现所谓的内存泄漏问。我再次定位问题,代码可能出在激光图层这一块,但是我使用官方的例子 也同样不会出现内存泄漏。 我和官方的不同,主要存在于 map 和 loca 对象都保存在 store 中。

1
2
3
4
5
6
7
8
// 获取store中的 loca
this.loca=store.getters.loca;
// 增加前十名
this.addTopLayer();
// 增加激光图层
this.addLaserLayer();
// 启动激光层,问题可能出在这个地方
this.loca.animate.start();

综上所述,问题可能出在不止一个地方。但是具体的哪里导致的内存泄漏,不得而知,

(1) 可能是启动animate
(2) 可能是将要素增加到地图上面

因为使用的是高德的api,所有的东西都是调用的高德的东西,那么问题到底出在哪里,只能去找高德了,但是奇怪就是奇怪在,我除了在项目中复现这个问题之外,单独的任何一个例子,都无法复现整个的问题,这个都没有办法给官方提问题。

4.省区bug

后来我又发现了新的线索,就是我在加载地图之前,记载了行政区划,进行了掩膜处理,如果我将这个掩膜去掉,效果就会好很多,也不会出现内存持续暴涨的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// 区域掩膜
const areaMask=()=>{
var provinces = [
'520000',//贵州
'540000',//西藏
'530000',//云南
'500000',//重庆
'360000',//江西
'340000',//安徽
'510000',//四川
'350000',//福建
'430000',//湖南
'420000', //湖北
'410000',//河南
'330000',//浙江
'640000',//宁夏
'650000',//新疆
'440000',//广东
'370000',//山东
'450000',//广西
'630000',//青海
'320000',//江苏
'140000',//山西
'460000',// 海南
'310000',//上海
'110000', // 北京
'130000', // 河北
'230000', // 黑龙江
'220000',// 吉林
'210000', //辽宁
'150000',//内蒙古
'120000',// 天津
'620000',// 甘肃
'610000',// 甘肃
'710000', //台湾
'810000', //香港
'820000' //澳门
]
// 显示行政区
var disLayer=new AMap.DistrictLayer.Province({
zIndex: 9,
adcode: provinces,
depth: 2,
styles: {
'fill': function (properties) {
// properties为可用于做样式映射的字段,包含
// NAME_CHN:中文名称
// adcode_pro
// adcode_cit
// adcode
var adcode = properties.adcode;
let color="rgba(0,0,0,0.7)";
if (adcode=='330110') {
color="";
}

return color;
},
'province-stroke': 'cornflowerblue',
'city-stroke': 'white', // 中国地级市边界
'county-stroke': function(properties){
var adcode = properties.adcode;
let color="";
if (adcode=='330110') {
color='rgba(255,255,255,1)';
}
return color;
}, // 中国区县边界
'stroke-width':function(properties){
var adcode = properties.adcode;
let width=0;
if (adcode=='330110') {
width=2;
}

return width;
},
}
});
// 添加到地图上
mainmap.addLayer(disLayer);

经过测试,果然会出现这样的内存泄漏问题。

测试的代码我已经放到网上,运行之后,替换 MapView 文件中的 serviceHost 和key,访问 http://localhost:8888/#/masklayer ,可以查看问题。

1
2
3
4
## 安装
pnpm install
## 运行
pnpm dev

后来官方的人员回复,说是可能是vue的问题,但是我把全部的代码,都从store里面拿出来了,还是不行啊,我甚至打开了官方例子,同样会出现系统内存被占满的问题,他们说,我看的不对,应该看浏览器的内存,不能看资源管理器的内容,但是我的系统资源的的确确是被这个页面拖垮的啊。打开 官方的其他的例子 圆点—全国粤菜分布情况 同样也不会出现这个问题。

目前我看只有devlop有这个问题,谷歌浏览器也会涨内存,但是到一定的值之后,内存就掉下来了,应该是释放掉了。

5.完整代码

我贴一下完整代码好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
<template>
<div class="mapContainer" id="mapContainer"></div>
</template>

<script>
import AMapLoader from '@amap/amap-jsapi-loader';

export default {
props:{
viewmode:{
type:String,
default:"2D",
},
pitch:{ // 倾斜角
type:Number,
default:0
}
},
setup(props){
const store=useStore();
let mainmap=null; // 主地图
let mainloca=null; // 主loca
window.forceWebGL = true; // 强制启动WebGL
// window.forceWebGLBaseRender = true; // 开启GL
window._AMapSecurityConfig = { // 加载密钥
serviceHost:'xxx'
}

// 区域掩膜
function areaMask(){
var provinces = [
'520000',//贵州
'540000',//西藏
'530000',//云南
'500000',//重庆
'360000',//江西
'340000',//安徽
'510000',//四川
'350000',//福建
'430000',//湖南
'420000', //湖北
'410000',//河南
'330000',//浙江
'640000',//宁夏
'650000',//新疆
'440000',//广东
'370000',//山东
'450000',//广西
'630000',//青海
'320000',//江苏
'140000',//山西
'460000',// 海南
'310000',//上海
'110000', // 北京
'130000', // 河北
'230000', // 黑龙江
'220000',// 吉林
'210000', //辽宁
'150000',//内蒙古
'120000',// 天津
'620000',// 甘肃
'610000',// 甘肃
'710000', //台湾
'810000', //香港
'820000' //澳门
]
// 显示行政区
var disLayer=new AMap.DistrictLayer.Province({
zIndex: 9,
adcode: provinces,
depth: 2,
styles: {
'fill': function (properties) {
// properties为可用于做样式映射的字段,包含
// NAME_CHN:中文名称
// adcode_pro
// adcode_cit
// adcode
var adcode = properties.adcode;
let color="rgba(0,0,0,0.7)";
if (adcode=='330110') {
color="";
}

return color;
},
'province-stroke': 'cornflowerblue',
'city-stroke': 'white', // 中国地级市边界
'county-stroke': function(properties){
var adcode = properties.adcode;
let color="";
if (adcode=='330110') {
color='rgba(255,255,255,1)';
}
return color;
}, // 中国区县边界
'stroke-width':function(properties){
var adcode = properties.adcode;
let width=0;
if (adcode=='330110') {
width=2;
}

return width;
},
}
});

// 添加到地图上
mainmap.addLayer(disLayer);
}
// 加载图层
function addLayer(){
// 创建 Loca 实例
let loca = mainloca;

let geojson={
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": 65,
"properties": {
"X": 120.18798209978567,
"Y": 30.48288207977986,
},
"geometry": {
"type": "Point",
"coordinates": [
120.192597,
30.480531
]
}
},
{
"type": "Feature",
"id": 66,
"properties": {
"X": 120.19579890040778,
"Y": 30.482233229669298,
},
"geometry": {
"type": "Point",
"coordinates": [
120.200392,
30.479869
]
}
}
]
}
// 创建数据源
let dataSource = new Loca.GeoJSONSource({
data: geojson,
});

// 加载点图层、创建圆点图层
let pointLayer = new Loca.PointLayer({
zIndex: 10,
opacity: 1,
visible: true,
blend: 'lighter',
zooms: [2, 16],
});
// 图层添加数据
pointLayer.setSource(dataSource);

// 添加地图
loca.add(pointLayer);
}

// 使用API加载高德地图
AMapLoader.load({
"key": "xxx", // 申请好的Web端开发者Key,首次调用 load 时必填
"version": "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
"plugins": ['Map3D','AMap.DistrictSearch','AMap.DistrictLayer'], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
"AMapUI": { // 是否加载 AMapUI,缺省不加载
"version": '1.1', // AMapUI 缺省 1.1
"plugins":[], // 需要加载的 AMapUI ui插件
},
"Loca":{ // 是否加载 Loca, 缺省不加载
"version": '2.0' // Loca 版本,缺省 1.3.2
},
}).then((AMap)=>{
// 加载地图
mainmap = new AMap.Map('mapContainer', {
mapStyle: 'amap://styles/8da0701c78123ad8ccfa967bf22a9397', //设置地图的显示样式
viewMode: '3D', // 默认使用 2D 模式,如果希望使用带有俯仰角的 3D 模式,请设置 viewMode: '3D',
zoom:11, //初始化地图层级
center: [119.978873,30.273852], //初始化地图中心点
pitch:60,
showBuildingBlock:true, // 显示3D楼宇
skyColor:'', // 天空颜色
});

mainloca=new Loca.Container({
map:mainmap
});

// 增加区域
areaMask();
// 执行图层加载
addLayer();

}).catch(e => {
console.log(e);
});
}
}
</script>

<style lang="scss">
.mapContainer{
height: 100%;
width: 100%;
border-radius: 4px;

.mapboxgl-ctrl-logo{
display:none!important;
}

.amap-logo,.amap-copyright{
display: none!important;
}

/** 图标 */
.amap-marker:first-child .amap-icon img {
width: 25px;
height: 34px;
}

}
</style>

5.总结

1.测试了谷歌、Edge浏览器、火狐浏览器,目前只有 Firfox Devloper Edition 浏览器会出现内存无法释放掉问题,其他浏览器在内存增长到一个阶段,内存就会被释放掉,不会拖垮电脑,Firfox Devloper Editon 会拖垮电脑。
2.问题代码主要是 AMap.DistrictLayer.Province 类,还有 Loca.PointLayer 类,并且两者同时出现时才会有问题,单独出现一个不会有问题,官方的其他代码目前暂时没有出现问题。
3.排除vue等一切问题之后,测试代码可以使用官方例子,也可以用我上面的例子。
4.官方目前没有更好的办法,只能是排期优化,我这么多天一直在苦心钻研的东西,最后竟然还是无法解决,真是可悲可叹啊。

小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。