JDK-8044851 : nashorn properties leak memory
  • Type: Bug
  • Component: core-libs
  • Sub-Component: jdk.nashorn
  • Affected Version: 8u40
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2014-06-04
  • Updated: 2015-01-21
  • Resolved: 2014-08-12
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u40Fixed 9 b28Fixed
Related Reports
Duplicate :  
Description
Adding and removing properties to an object leaks memory. A test program (adapted from node's test/simple/test-event-emitter-memory-leak.js) follows -

var Thread = java.lang.Thread;
var runtime = java.lang.Runtime.getRuntime();
var mb = 1024 * 1024;

var noop = function() {};
var map = {};

runtime.gc();
Thread.sleep(1000);
var before = runtime.freeMemory();
print('before ' + before / mb);
for (var i = 0; i < 16e5; ++i) {
  var name = 'a-pretty-long-event-name-zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz-' + i;
  map[name] = noop;
  delete map[name];
  if ((i % 1e5) === 0) {
    runtime.gc();
    print('       ' + (runtime.freeMemory() - before) / mb);
  }
}
runtime.gc();
Thread.sleep(1000);
var after = runtime.freeMemory();
print('after  ' + after / mb);
print('leaked ' + ((after - before) / mb));

when run as 'jjs -J-Xms1g -J-Xmx1g leak.js' can be observed to increase its resident size steadily as the program progresses, and prints freeMemory which is seen as steadily decreasing -

before 966.2640838623047
       7.783241271972656
       44.487510681152344
       45.94429016113281
       46.042991638183594
       45.18035125732422
       44.3046875
       43.93107604980469
       43.05583953857422
       42.19343566894531
       41.37696075439453
       40.98670196533203
       40.12110137939453
       39.256675720214844
       38.39038848876953
       37.998321533203125
       37.12486267089844
after  1001.1347503662109
leaked 34.87066650390625

Comments
We have two ways to fix this, one simple but incomplete, the other a bit more involved but complete. The simple fix is to special case deletion of the last added spill slot to free the slot in the new property map. (Even better would be to just reuse the predecessor map, but for that we'd have to add back references to the predecessor map.) This solution would fix the problem in the test case and in all code where the last added property is deleted. To solve this problem for the general case we'd have to make sure all deleted slots can be reused. I'm currently thinking about different approaches for this: - keeping a list of freed slots. Simple and fast but requires memory. - searching for free slots when property is added based on some HAS_DELETED_SLOTS flag and map size. Could be prohibitive for very large objects. - compressing large maps when some size/deletion threshold is crossed. This means we also have to update the object(s) using this map, which creates a few new problems (also in regard to concurrency).
30-07-2014

Not reusing slots once deleted.
05-06-2014