arcgis javascript memory leak

4977
18
10-11-2018 03:38 AM
weili7
by
New Contributor II

I'm trying use client-side feature layer to display tweenty thounds polygon on map, i need add/remove layer frenquenly, i found when a add some layer then remove all of it, chrome memory usage only decrese a small part of it increase. 

there is some code of my app:

create map and mapview:

cosnt map = new Map({
  basemap: 'osm'
})
const mapView = new MapView({
  container: 'viewDiv',
  map,
  center: [xx, yy],
  zoom: 5
})

add layer:

const graphics = _.map(grids, (grid) => ({
  geometry: new Polygon({
    hasZ: false,
    hasM: false,
    rings: grid.ring
  }),

  attributes: {
    ObjectID: grid.id
  }
}))

const layer = new FeatureLayer({
  source: graphics,
  fields, 
  objectIdField: 'ObjectID',
  renderer: renderer, 
  popupTemplate: pTemplate
})
 map.add(layer)

clear layer:

map.removeAll()

I found if i not create MapView(only create Map, and add/remove layer on map) it works fine, does it means i miss call some method on MapView to clear?

============== Update =================

i debug use chrome dev tool memory snapshot, i found when i add then remove layer, there a some object left, e.g. 4.9/esri/layers/graphics/data/DefaultSpatialIndex.js file _.featuresById field, the clean method not called.

0 Kudos
18 Replies
AndrewMurdoch1
Occasional Contributor II

You're describing exactly what our problem is!  We have several areas where we build up rather complex maps with thousands of sections and assets on them, including Widgets, and no matter what I flush, free, null, destroy or delete, we always have ~100 - 200 MB of memory kicking around from each map, that I can't get rid of.

In most cases this isn't an issue because people don't use our software long enough or cycle through enough maps to create an issue, but it's 100 - 200 MB each time you visit a map, so if you work with the maps for a couple hours and cycle them 10 - 15 times, you're easily holding 1GB - 2GB of memory that we have no way to free.

If you come up with a solution please let me know, because apart from refreshing the site I don't know what to do.  I'll take a look at your example, but I suspect I'm doing exactly the same thing - 🙂

Cheers

AndrewMurdoch1
Occasional Contributor II

Your map-service is doing the same thing our esri-service is doing, so at least we approached the problem from the same angle!

0 Kudos
NilsBabel1
Occasional Contributor

Thanks Andrew, at least I know I'm not crazy.  I only really determined it was a problem because I noticed each time the user went back to the map the performance of the map was degraded.  Also, if I repeatedly test going back and forth to the map eventually (~10-15 visits) I get a webGL error (number of webGL contexts has reached it's limit, the last context will be lost).  So it's not just that the map view is kept in memory but there is a webGL context for each map view.  Another very odd thing I noticed is I have an identify task and I walked through the code for when you click the map.  The identify task gets called once for each map component I  built.  So if I have gone back to my map page three times the identify task gets called three times for each click.  So it seems the 'old' map views don't actually go away.  They still have a webGL context and are still there even though you don't see them in the DOM.  Any ideas on how to communicate this to esri?  It seems like it should be something on their end and we shouldn't be jumping through hoops to try and fix this.  

 

0 Kudos
AndrewMurdoch1
Occasional Contributor II

Well you've been talking with Andy whose fairly responsive, and that's good!  I know at a few other ESRI dev's know about this, and I've given them a couple test repo's to demonstrate the issue, so I'm not sure what else we can do.

Apart from refreshing, which is certainly not ideal, I think we're stuck until they figure out a solution on their end.

0 Kudos
NilsBabel1
Occasional Contributor

Hey @AndrewMurdoch1 I've made some progress on the memory leak in my app.  I've successfully gotten the view to completely destroy.  When the user goes back to the map component it displays the existing map view and there is only one object in the memory snapshot. 

On ngOnDestroy I had to destroy, remove, and nullify everything that contains any reference to the map view.  For widgets I run destroy() and  make null.  Some objects besides widgets retain a reference to the view somehow also.  I create a PortalBasemapSource and even though there is no reference to the view I had to destroy and make it null also.  I think anything in the API that you create with the new keyword should be destroyed and made null. 

I also created and event handler for every event (.on(...)) I've created on the view, widgets, and watchUtils.  Then in ngOnDestroy I call remove() on all the handlers.  It was a brutal effort of trial and error but in this case I've got it working.  I guess this makes sense.  I think the api is doing what it is supposed to.  I think it's more of an issue with angular/javascript garbage collection.  Not sure how many things you have going on in your map but if you can destroy them or remove them onDestroy than you may be able to fix your memory leak.  

As an extra tidbit I'm using the Angular Material Drag and Drop Directive (https://material.angular.io/cdk/drag-drop/overview).  At version 8.2.3 it has a memory leak in the dragboundary property (https://github.com/angular/components/issues/17255).  Took me a while to figure that out since I'm putting my widgets in a div that the user can drag around.  You might check that too, if you are using it.

 

Good luck!

AndrewMurdoch1
Occasional Contributor II

I'll try that on my end, I was doing some similar in 4.15 / 4.16 of the ArcGIS lib, but maybe things got better in 4.17+.

Thanks for the tip!

Cheers

0 Kudos
AndrewMurdoch1
Occasional Contributor II

Sorry, I totally spaced on this ticket!  I changed our code over to use ArcGIS Core from:

https://github.com/Esri/jsapi-resources/tree/master/esm-samples

I used that to create this example:

https://github.com/docmur/angular-core-esri

I accidentally left it running for 60 hours last weekend and overall the memory was fine.  It grabbed a little for the map, but otherwise didn't grab anymore.

Take a look and see if you can make it work 🙂

0 Kudos
AndrewMurdoch1
Occasional Contributor II

I know this an old post, but I got it!  

1. Look at https://github.com/epaitz/jsapi-angular-ngrx-ds2021
2. I took that code and made:  https://github.com/docmur/angular-core-esri (Look at master-a12)
3. When you allocate a map, store it's "settings" in a Store (map, view, feature layers, etc…)
4. When you recall the map, don't allocate a new feature layer, just remove and add the features to the existing layer(s) if you need to change the layer or features.
5.  That code is using a single map and view, then changing the features in the layer, but the same idea works for multiple maps.
6.  Don't try and destroy the map or view, or feature layer, you won't reclaim memory doing that.

For some reason the featureLayer.destroy(), and map.removeAll() / map.layers.removeAll(), won't free the memory being held by the feature layer, which is why it continues to climb.  I've already rolled this code into our production application, and it works wonderfully!  We allocate 2 maps in total, and then just hold them in the Store, being recalled when we need them, then I use the feature layer to apply edits to do the main work.

The multiple map variation has been able to run for 20+ hours with no issue and using ~35MB of memory from the Dev Console.

This is the solution you're probably looking for 🙂

Cheers

NilsBabel1
Occasional Contributor

Thanks a lot.  I'll take a look.

0 Kudos