{"action":"created","issue":{"url":"https://api.github.com/repos/togglz/togglz/issues/157","repository_url":"https://api.github.com/repos/togglz/togglz","labels_url":"https://api.github.com/repos/togglz/togglz/issues/157/labels{/name}","comments_url":"https://api.github.com/repos/togglz/togglz/issues/157/comments","events_url":"https://api.github.com/repos/togglz/togglz/issues/157/events","html_url":"https://github.com/togglz/togglz/issues/157","id":150789017,"number":157,"title":"JavaScript evaluation seems to eat memory","user":{"login":"piefel","id":1384302,"avatar_url":"https://avatars.githubusercontent.com/u/1384302?v=3","gravatar_id":"","url":"https://api.github.com/users/piefel","html_url":"https://github.com/piefel","followers_url":"https://api.github.com/users/piefel/followers","following_url":"https://api.github.com/users/piefel/following{/other_user}","gists_url":"https://api.github.com/users/piefel/gists{/gist_id}","starred_url":"https://api.github.com/users/piefel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/piefel/subscriptions","organizations_url":"https://api.github.com/users/piefel/orgs","repos_url":"https://api.github.com/users/piefel/repos","events_url":"https://api.github.com/users/piefel/events{/privacy}","received_events_url":"https://api.github.com/users/piefel/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2016-04-25T08:39:15Z","updated_at":"2016-04-26T14:05:50Z","closed_at":null,"body":"Recently, I had a case when I wanted to choose the new or the old variant of a certain feature based on a percentage, and I used Togglz and the Java Scripting API activation strategy for it. I used the following JavaScript: `Math.random() < Math.pow(1 - (27 - date.getDate()) * 0.2, 3)` to increase usage day by day.\r\n\r\nHowever, this decision is made _often_ in the code, and there seems to be a leak. To demonstrate, consider the following code:\r\n\r\n    Stopwatch stopwatch = Stopwatch.createStarted();\r\n    int active = 0;\r\n    for (int i = 0; i < 1000; i++) {\r\n        if (Features.NEW_EXPERIMENT.isActive()) active += 1;\r\n    }\r\n    stopwatch.stop();\r\n    log.debug(\"{}% -- {} -- {} MB free\", active / 10,\r\n            stopwatch, Runtime.getRuntime().freeMemory() / 1024 / 1024);\r\n\r\nI let this run with a fixed delay of two seconds, and the log went like:\r\n\r\n    100% -- 5.181 s -- 1124 MB free\r\n    100% -- 2.871 s -- 767 MB free\r\n    100% -- 3.559 s -- 837 MB free\r\n    100% -- 2.401 s -- 543 MB free\r\n    100% -- 2.771 s -- 611 MB free\r\n    100% -- 4.087 s -- 1138 MB free\r\n    100% -- 2.574 s -- 962 MB free\r\n    100% -- 2.698 s -- 751 MB free\r\n    100% -- 2.817 s -- 543 MB free\r\n    100% -- 3.107 s -- 1002 MB free\r\n    100% -- 3.283 s -- 670 MB free\r\n    100% -- 3.135 s -- 407 MB free\r\n    100% -- 5.170 s -- 289 MB free\r\n    100% -- 5.462 s -- 115 MB free\r\n    100% -- 5.991 s -- 33 MB free\r\n\r\nThen it even worse… It seems the GC was not able to keep up.\r\n\r\nThis was probably an abuse of Togglz. Had I had more time and been able to fire a new deployment on the server, I would have used a custom activation strategy instead. Perhaps a small warning in the docs would be helpful."},"comment":{"url":"https://api.github.com/repos/togglz/togglz/issues/comments/214756370","html_url":"https://github.com/togglz/togglz/issues/157#issuecomment-214756370","issue_url":"https://api.github.com/repos/togglz/togglz/issues/157","id":214756370,"user":{"login":"piefel","id":1384302,"avatar_url":"https://avatars.githubusercontent.com/u/1384302?v=3","gravatar_id":"","url":"https://api.github.com/users/piefel","html_url":"https://github.com/piefel","followers_url":"https://api.github.com/users/piefel/followers","following_url":"https://api.github.com/users/piefel/following{/other_user}","gists_url":"https://api.github.com/users/piefel/gists{/gist_id}","starred_url":"https://api.github.com/users/piefel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/piefel/subscriptions","organizations_url":"https://api.github.com/users/piefel/orgs","repos_url":"https://api.github.com/users/piefel/repos","events_url":"https://api.github.com/users/piefel/events{/privacy}","received_events_url":"https://api.github.com/users/piefel/received_events","type":"User","site_admin":false},"created_at":"2016-04-26T14:05:50Z","updated_at":"2016-04-26T14:05:50Z","body":"I might have found one problem in your code, though. You get a new instance of the scripting engine on each decision. This is probably unnessary, one (perhaps `ThreadLocal`) should be enough. When I patched the routine to get the ECMAScript engine only once, the following values came up (for the more involved JavaScript expression):\r\n\r\n    52% - 36.23 ms -- 269 MB free\r\n    51% - 32.87 ms -- 265 MB free\r\n    52% - 24.06 ms -- 263 MB free\r\n    49% - 17.55 ms -- 259 MB free\r\n    51% - 20.47 ms -- 256 MB free\r\n    53% - 7.622 ms -- 254 MB free\r\n    52% - 7.349 ms -- 251 MB free\r\n    53% - 6.611 ms -- 248 MB free\r\n    51% - 7.397 ms -- 245 MB free\r\n    47% - 6.773 ms -- 242 MB free\r\n    54% - 6.606 ms -- 239 MB free\r\n    50% - 6.629 ms -- 236 MB free\r\n    48% - 6.610 ms -- 229 MB free\r\n\r\nThis is without explicit GCs now. Curiously the free memory is much lower here, don’t know why, probably some completely unrelated effect. Anyway, it’s now taking milliseconds (getting faster all the time, even) instead of seconds to perform the 1000 calls. Memory consumptions stays the same, the thread works on and on (over 100 runs up to now and counting)."}}