Firstly, see here: https://github.com/AnalyticalGraphicsInc/cesium/blob/1.13/Source/Core/AssociativeArray.js#L108
It may be worth considering changing:
this._hash[key] = undefined;
to
delete this._hash[key];
As it currently creates a large number of 'key: undefined' entries when you delete a large number of entities.
However, this isn't the memory leak I am talking about.
Currently, if you add and then remove a large number of entities (as you may have to in live data displays, for example), the memory usage builds up.
It appears that a reference to the entities is still stored in a GeometryVisualiser so they are not cleared by the GC.
For example, after creating and deleting 5000 entities I could still see 5000 entities in:
testDataSource._visualizers[1]._primitives._primitives[0]._pickIds
and
testDataSource._visualizers[1]._primitives._primitives[0]._instanceIds
Running remove() on the EntityCollection does not appear to correctly remove the data from the primitives. And they appeared to be references in most of the visualizers.
This breaks my usage of Cesium as I am using it for live data, so I need to create and delete entities regularly. Is there any workaround for this? Is this something that you guys are already aware of?
I have included sandcastle code below for replicating the issue. It prints out the collection to console after each change, so if you are using chrome you should be able to view the datasource in the console and notice how the primitives under visualizers are holding on to a reference to the entities.
Creating and deleting 20k entities and then running a javascript Heap Profile in chrome will show you a large amount of memory retained in Entity objects.
If you wish to replicate it, paste the following HTML into the sandcastle:
<style>
@import url(../templates/bucket.css);
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar">
<div id="addEntities"></div>
<div id="removeAllEntities"></div>
</div>
And paste the following javascript into the sandcastle:
var viewer = new Cesium.Viewer('cesiumContainer');
var testDataSource = new Cesium.CustomDataSource('test');
viewer.dataSources.add(testDataSource);
var createQuantity = 5000;
var created = 0;
var deleted = 0;
// Add entities
function addEntities(){
for (var i = created; i < (created + createQuantity); i++) {
var entity = testDataSource.entities.getById(i);
var lng = -80.12;
var lat = 25.46;
var name = 'test' + i;
var type = 'type' + i;
var description = ' test description words ' + i +
' test description words ' + i +
' test description words ' + i +
' test description words ' + i +
' test description words ' + i;
// If no heat dot found, create it
if (typeof entity === 'undefined') {
entity = testDataSource.entities.add({
id: i,
name: name,
entityType: type,
description: description,
rectangle: {
coordinates: Cesium.Rectangle.fromDegrees(lng - 0.0001, lat - 0.0001,
lng + 0.0001, lat + 0.0001),
material: Cesium.Color.WHITE.withAlpha(0.5),
extrudedHeight: 100
}
});
}
}
created = created + createQuantity;
console.log(testDataSource);
}
// Remove all
function removeAllEntities(){
for (var i = 0; i < testDataSource.entities.values.length; i++) {
var entity = testDataSource.entities.values[i];
testDataSource.entities.remove(entity);
deleted += 1;
i--;
}
console.log(testDataSource);
}
Sandcastle.addToolbarButton('Add ' + createQuantity + ' Entities', function() {
addEntities();
console.log('Created: ' + created);
}, 'addEntities');
Sandcastle.addToolbarButton('Remove All Entities', function() {
removeAllEntities();
console.log('Deleted: ' + deleted);
}, 'removeAllEntities');