memory.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. module.metadata = {
  6. "stability": "deprecated"
  7. };
  8. const { Cc, Ci, Cu, components } = require("chrome");
  9. const { when: unload } = require("../system/unload")
  10. var trackedObjects = {};
  11. const Compacter = {
  12. notify: function() {
  13. var newTrackedObjects = {};
  14. for (let name in trackedObjects) {
  15. let oldBin = trackedObjects[name];
  16. let newBin = [];
  17. let strongRefs = [];
  18. for (let i = 0, l = oldBin.length; i < l; i++) {
  19. let strongRef = oldBin[i].weakref.get();
  20. if (strongRef && strongRefs.indexOf(strongRef) == -1) {
  21. strongRefs.push(strongRef);
  22. newBin.push(oldBin[i]);
  23. }
  24. }
  25. if (newBin.length)
  26. newTrackedObjects[name] = newBin;
  27. }
  28. trackedObjects = newTrackedObjects;
  29. }
  30. };
  31. var timer = Cc["@mozilla.org/timer;1"]
  32. .createInstance(Ci.nsITimer);
  33. timer.initWithCallback(Compacter,
  34. 5000,
  35. Ci.nsITimer.TYPE_REPEATING_SLACK);
  36. function track(object, bin, stackFrameNumber) {
  37. var frame = components.stack.caller;
  38. var weakref = Cu.getWeakReference(object);
  39. if (!bin && 'constructor' in object)
  40. bin = object.constructor.name;
  41. if (bin == "Object")
  42. bin = frame.name;
  43. if (!bin)
  44. bin = "generic";
  45. if (!(bin in trackedObjects))
  46. trackedObjects[bin] = [];
  47. if (stackFrameNumber > 0)
  48. for (var i = 0; i < stackFrameNumber; i++)
  49. frame = frame.caller;
  50. trackedObjects[bin].push({weakref: weakref,
  51. created: new Date(),
  52. filename: frame.filename,
  53. lineNo: frame.lineNumber,
  54. bin: bin});
  55. }
  56. exports.track = track;
  57. var getBins = exports.getBins = function getBins() {
  58. var names = [];
  59. for (let name in trackedObjects)
  60. names.push(name);
  61. return names;
  62. };
  63. function getObjects(bin) {
  64. var results = [];
  65. function getLiveObjectsInBin(bin) {
  66. for (let i = 0, l = bin.length; i < l; i++) {
  67. let object = bin[i].weakref.get();
  68. if (object) {
  69. results.push(bin[i]);
  70. }
  71. }
  72. }
  73. if (bin) {
  74. if (bin in trackedObjects)
  75. getLiveObjectsInBin(trackedObjects[bin]);
  76. }
  77. else {
  78. for (let name in trackedObjects)
  79. getLiveObjectsInBin(trackedObjects[name]);
  80. }
  81. return results;
  82. }
  83. exports.getObjects = getObjects;
  84. function gc() {
  85. // Components.utils.forceGC() doesn't currently perform
  86. // cycle collection, which means that e.g. DOM elements
  87. // won't be collected by it. Fortunately, there are
  88. // other ways...
  89. var test_utils = Cc["@mozilla.org/appshell/appShellService;1"]
  90. .getService(Ci.nsIAppShellService)
  91. .hiddenDOMWindow
  92. .QueryInterface(Ci.nsIInterfaceRequestor)
  93. .getInterface(Ci.nsIDOMWindowUtils);
  94. test_utils.garbageCollect();
  95. // Clean metadata for dead objects
  96. Compacter.notify();
  97. // Not sure why, but sometimes it appears that we don't get
  98. // them all with just one CC, so let's do it again.
  99. test_utils.garbageCollect();
  100. };
  101. exports.gc = gc;
  102. unload(_ => {
  103. trackedObjects = {};
  104. if (timer) {
  105. timer.cancel();
  106. timer = null;
  107. }
  108. });