{"action":"created","issue":{"url":"https://api.github.com/repos/nodejs/node/issues/3113","labels_url":"https://api.github.com/repos/nodejs/node/issues/3113/labels{/name}","comments_url":"https://api.github.com/repos/nodejs/node/issues/3113/comments","events_url":"https://api.github.com/repos/nodejs/node/issues/3113/events","html_url":"https://github.com/nodejs/node/issues/3113","id":108878621,"number":3113,"title":"VM: Extreme memory growth","user":{"login":"arthurschreiber","id":2195,"avatar_url":"https://avatars.githubusercontent.com/u/2195?v=3","gravatar_id":"","url":"https://api.github.com/users/arthurschreiber","html_url":"https://github.com/arthurschreiber","followers_url":"https://api.github.com/users/arthurschreiber/followers","following_url":"https://api.github.com/users/arthurschreiber/following{/other_user}","gists_url":"https://api.github.com/users/arthurschreiber/gists{/gist_id}","starred_url":"https://api.github.com/users/arthurschreiber/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/arthurschreiber/subscriptions","organizations_url":"https://api.github.com/users/arthurschreiber/orgs","repos_url":"https://api.github.com/users/arthurschreiber/repos","events_url":"https://api.github.com/users/arthurschreiber/events{/privacy}","received_events_url":"https://api.github.com/users/arthurschreiber/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/nodejs/node/labels/memory","name":"memory","color":"eb6420"},{"url":"https://api.github.com/repos/nodejs/node/labels/vm","name":"vm","color":"bfdadc"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":16,"created_at":"2015-09-29T14:13:35Z","updated_at":"2015-09-29T20:22:56Z","closed_at":null,"body":"It looks like `context` objects are not collected by the GC until the max memory limit is reached.\r\n\r\n```js\r\n'use strict';\r\n\r\nvar vm = require('vm');\r\n\r\nvar script = vm.createScript();\r\nvar context = vm.createContext();\r\n\r\nfor (var i = 0; i < 10000000; i++) {\r\n  vm.runInNewContext('(_$_v.length-1)', {\r\n    '_$_v': [\r\n      { category: 'reference',\r\n        author: 'Nigel Rees',\r\n        title: 'Sayings of the Century',\r\n        price: 8.95 },\r\n      { category: 'fiction',\r\n        author: 'Evelyn Waugh',\r\n        title: 'Sword of Honour',\r\n        price: 12.99 },\r\n      { category: 'fiction',\r\n        author: 'Herman Melville',\r\n        title: 'Moby Dick',\r\n        isbn: '0-553-21311-3',\r\n        price: 8.99 },\r\n      { category: 'fiction',\r\n        author: 'J. R. R. Tolkien',\r\n        title: 'The Lord of the Rings',\r\n        isbn: '0-395-19395-8',\r\n        price: 22.99 }\r\n    ]\r\n  });\r\n\r\n  if (i % 10 === 0) {\r\n    console.log(\"After\", i, \"iterations:\", parseInt(process.memoryUsage().heapTotal / 1024 / 1024), \"MB\");\r\n  }\r\n}\r\n```\r\n\r\n```\r\n$ node test.js\r\nAfter 0 iterations: 9 MB\r\nAfter 10 iterations: 20 MB\r\nAfter 20 iterations: 30 MB\r\nAfter 30 iterations: 46 MB\r\nAfter 40 iterations: 52 MB\r\nAfter 50 iterations: 60 MB\r\nAfter 60 iterations: 69 MB\r\nAfter 70 iterations: 95 MB\r\nAfter 80 iterations: 101 MB\r\nAfter 90 iterations: 107 MB\r\nAfter 100 iterations: 114 MB\r\nAfter 110 iterations: 120 MB\r\nAfter 120 iterations: 126 MB\r\nAfter 130 iterations: 137 MB\r\nAfter 140 iterations: 142 MB\r\nAfter 150 iterations: 154 MB\r\nAfter 160 iterations: 159 MB\r\nAfter 170 iterations: 166 MB\r\nAfter 180 iterations: 178 MB\r\nAfter 190 iterations: 184 MB\r\nAfter 200 iterations: 191 MB\r\nAfter 210 iterations: 203 MB\r\nAfter 220 iterations: 208 MB\r\nAfter 230 iterations: 221 MB\r\nAfter 240 iterations: 227 MB\r\nAfter 250 iterations: 234 MB\r\nAfter 260 iterations: 245 MB\r\nAfter 270 iterations: 253 MB\r\nAfter 280 iterations: 265 MB\r\nAfter 290 iterations: 270 MB\r\nAfter 300 iterations: 277 MB\r\nAfter 310 iterations: 288 MB\r\nAfter 320 iterations: 296 MB\r\nAfter 330 iterations: 302 MB\r\nAfter 340 iterations: 313 MB\r\nAfter 350 iterations: 320 MB\r\nAfter 360 iterations: 333 MB\r\nAfter 370 iterations: 339 MB\r\nAfter 380 iterations: 346 MB\r\nAfter 390 iterations: 357 MB\r\nAfter 400 iterations: 363 MB\r\nAfter 410 iterations: 365 MB\r\nAfter 420 iterations: 365 MB\r\nAfter 430 iterations: 365 MB\r\nAfter 440 iterations: 365 MB\r\nAfter 450 iterations: 365 MB\r\nAfter 460 iterations: 367 MB\r\nAfter 470 iterations: 370 MB\r\nAfter 480 iterations: 376 MB\r\nAfter 490 iterations: 385 MB\r\nAfter 500 iterations: 392 MB\r\n```\r\n\r\nIf I specify `--max-old-space-size` I can stop the memory growth.\r\n\r\n```\r\n node --max-old-space-size=32 test2.js\r\nAfter 0 iterations: 9 MB\r\nAfter 10 iterations: 20 MB\r\nAfter 20 iterations: 39 MB\r\nAfter 30 iterations: 44 MB\r\nAfter 40 iterations: 10 MB\r\nAfter 50 iterations: 20 MB\r\nAfter 60 iterations: 30 MB\r\nAfter 70 iterations: 47 MB\r\nAfter 80 iterations: 17 MB\r\nAfter 90 iterations: 25 MB\r\nAfter 100 iterations: 31 MB\r\nAfter 110 iterations: 47 MB\r\nAfter 120 iterations: 15 MB\r\nAfter 130 iterations: 26 MB\r\n```\r\n\r\nIf I rewrite the code to reuse the context object, memory usage and performance are a lot better:\r\n\r\n```\r\n'use strict';\r\n\r\nvar vm = require('vm');\r\n\r\nvar script = vm.createScript('(_$_v.length-1)');\r\nvar context = vm.createContext();\r\n\r\nfor (var i = 0; i < 10000000; i++) {\r\n  context['_$_v'] = [\r\n    { category: 'reference',\r\n      author: 'Nigel Rees',\r\n      title: 'Sayings of the Century',\r\n      price: 8.95 },\r\n    { category: 'fiction',\r\n      author: 'Evelyn Waugh',\r\n      title: 'Sword of Honour',\r\n      price: 12.99 },\r\n    { category: 'fiction',\r\n      author: 'Herman Melville',\r\n      title: 'Moby Dick',\r\n      isbn: '0-553-21311-3',\r\n      price: 8.99 },\r\n    { category: 'fiction',\r\n      author: 'J. R. R. Tolkien',\r\n      title: 'The Lord of the Rings',\r\n      isbn: '0-395-19395-8',\r\n      price: 22.99 }\r\n  ];\r\n\r\n  script.runInContext(context);\r\n\r\n  if (i % 10000 === 0) {\r\n    console.log(\"After\", i, \"iterations:\", parseInt(process.memoryUsage().heapTotal / 1024 / 1024), \"MB\");\r\n  }\r\n}\r\n```\r\n\r\n```\r\n$ node test.js\r\nAfter 0 iterations: 9 MB\r\nAfter 10000 iterations: 11 MB\r\nAfter 20000 iterations: 11 MB\r\nAfter 30000 iterations: 12 MB\r\nAfter 40000 iterations: 13 MB\r\nAfter 50000 iterations: 13 MB\r\nAfter 60000 iterations: 13 MB\r\nAfter 70000 iterations: 13 MB\r\nAfter 80000 iterations: 13 MB\r\nAfter 90000 iterations: 13 MB\r\nAfter 100000 iterations: 13 MB\r\nAfter 110000 iterations: 14 MB\r\nAfter 120000 iterations: 14 MB\r\nAfter 130000 iterations: 15 MB\r\nAfter 140000 iterations: 16 MB\r\nAfter 150000 iterations: 17 MB\r\nAfter 160000 iterations: 17 MB\r\nAfter 170000 iterations: 18 MB\r\nAfter 180000 iterations: 19 MB\r\nAfter 190000 iterations: 20 MB\r\nAfter 200000 iterations: 20 MB\r\nAfter 210000 iterations: 21 MB\r\nAfter 220000 iterations: 22 MB\r\nAfter 230000 iterations: 22 MB\r\nAfter 240000 iterations: 23 MB\r\nAfter 250000 iterations: 23 MB\r\nAfter 260000 iterations: 23 MB\r\nAfter 270000 iterations: 23 MB\r\nAfter 280000 iterations: 23 MB\r\nAfter 290000 iterations: 23 MB\r\nAfter 300000 iterations: 23 MB\r\nAfter 310000 iterations: 23 MB\r\nAfter 320000 iterations: 23 MB\r\nAfter 330000 iterations: 23 MB\r\nAfter 340000 iterations: 23 MB\r\nAfter 350000 iterations: 23 MB\r\nAfter 360000 iterations: 23 MB\r\nAfter 370000 iterations: 23 MB\r\nAfter 380000 iterations: 19 MB\r\nAfter 390000 iterations: 19 MB\r\nAfter 400000 iterations: 19 MB\r\nAfter 410000 iterations: 19 MB\r\nAfter 420000 iterations: 19 MB\r\nAfter 430000 iterations: 19 MB\r\nAfter 440000 iterations: 19 MB\r\nAfter 450000 iterations: 19 MB\r\nAfter 460000 iterations: 19 MB\r\nAfter 470000 iterations: 19 MB\r\nAfter 480000 iterations: 19 MB\r\nAfter 490000 iterations: 19 MB\r\nAfter 500000 iterations: 19 MB\r\nAfter 510000 iterations: 20 MB\r\nAfter 520000 iterations: 20 MB\r\nAfter 530000 iterations: 21 MB\r\nAfter 540000 iterations: 22 MB\r\n```\r\n\r\nI understand why performance is a lot better (re-using the same object is obviously faster than creating new ones), but why is the memory profile so different?"},"comment":{"url":"https://api.github.com/repos/nodejs/node/issues/comments/144181049","html_url":"https://github.com/nodejs/node/issues/3113#issuecomment-144181049","issue_url":"https://api.github.com/repos/nodejs/node/issues/3113","id":144181049,"user":{"login":"ChALkeR","id":291301,"avatar_url":"https://avatars.githubusercontent.com/u/291301?v=3","gravatar_id":"","url":"https://api.github.com/users/ChALkeR","html_url":"https://github.com/ChALkeR","followers_url":"https://api.github.com/users/ChALkeR/followers","following_url":"https://api.github.com/users/ChALkeR/following{/other_user}","gists_url":"https://api.github.com/users/ChALkeR/gists{/gist_id}","starred_url":"https://api.github.com/users/ChALkeR/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ChALkeR/subscriptions","organizations_url":"https://api.github.com/users/ChALkeR/orgs","repos_url":"https://api.github.com/users/ChALkeR/repos","events_url":"https://api.github.com/users/ChALkeR/events{/privacy}","received_events_url":"https://api.github.com/users/ChALkeR/received_events","type":"User","site_admin":false},"created_at":"2015-09-29T20:22:56Z","updated_at":"2015-09-29T20:22:56Z","body":"@arthurschreiber It could be related, but just by modifying the destructor you can't solve this problem.\r\nThe destructor does not get called until the GC collects that object, and GC doesn't collect that object until a full mark-sweep, and those aren't triggered currently."}}