Javascript memory leak on page refresh; remedy? - javascript

I am experiencing a memory leak in IE that occurs upon a page refresh (as I described in this SO post).
All I want to know at this point is: is there a way, on the document "unload" event (which could get called when the page refreshes or closes), to clear EVERYTHING? I'm looking for a simple solution that would ensure that everything gets destroyed in order to avoid the leak. Is this even possible, or do I have to continue looking into the details of the leak and fixing it on an object by object basis?
Update: Ok maybe I wasn't descriptive enough. I can't (at least I dont think I can) just set all of my objects to null: I have event handlers for click events etc. so the application needs to be "live" constantly until it is closed. Also if I then think about just nulling everything out in an "unload" method (called when the page is exited), then all my objects would have to have global scope (right)? What is the best way to remedy this? Is there a way to get a list of all referenced objects so I can null them? Should I add every object I use to an array so that I can dereference it later?

try window.onbeforeunload or window.onunload and set the variables you use to null.
or you looking for something more?

Set your objects to null and they won't be leaked.

check if you are using a random anti-cache URL parameter, it might cause memory leaks
IE tries to keep all scripts loaded from the same domain in memory as you navigate from page to page, because there is a high chance that being on different pages you will be needing pretty much the same scripts.
a random anti-cache parameter added to the URL of a script makes it a different script (at least caching is fooled by that)
as we know IE tries to load all possible scripts for the domain and keep them
a random anti-cache parameters leads to memory leaks because every time otherwise the same scripts have a different URL and IE thinks they are different and downloads them over and over on each reload and keeps them in memory

Related

How to keep the scope or carry vars over when changing the website with JS

I am writing a simple clickbot in JavaScript to perform repetitive tasks on a 3rd party website. It just sets input values, calls the click() method of buttons and maybe I'll have it navigate to other URLs of the same website. I initially used Firefox but got the same behaviour with Internet Explorer.
I use plain JS so far and as long as I paste in every command by myself everything works fine but here's the problem: Any time a new page is loaded (including when JS clicks a submit button) I lose all vars and functions I defined. Note that I use the web console as opposed to a <script> tag that obyiousely would be dropped when a new DOM is loaded.
Honestly, I do not entirely understand why this happens. I looked at JavaScript scope and the documentation of window.location and document.location. This site even mentioned that "In a web browser, global variables are deleted when you close the browser window (or tab), but remain available to new pages loaded into the same window." (cf. here, but that's not the point here)
I thought it might be because strict mode might be enabled by default but that would have raised an error for name = "value" instead of silently interpreting it as a local variable.
According to this answer, any var declared outside any methods should be globals that are properties of window. Changing another propertie of window (e.g. location) should not affect them - as far as my reasoning goes - but even when assigning properties myself, they disappear when I load another page.
I suppose it could be worked around if I wrote my own website that has the site I need as an iFrame so the page my script runs on would not actually be changed. But still this is strange. Can anyone explain this behaviour? Is there another (easy) way around it?
[Edit1] Thanks to same-origine policy my proposed workaround using an own website and iframe does not work. Since the whole point of my clickbot is to be started once and click through all pages on it's own, a way to carry on data (i.e. strings including JSON) is answering this question but does not solve my problem.
[Edit2] For future visitors: After recent edits, the accepted answer does provide all information I needed. Greasemonkey is the way to go if you can use addons but the combination of bookmarklets and sessionStorage stil allow for a decent bot that performes all steps between two reloads with just one user input. Another (ugly bot possibly more powerfull) approach is to open the target website and use document.body.innerHTML and the iframe workaround. That way you bypass the same-origine policy and can build your own website as needed and still access the target website.
Regarding the lifetime of a variable this SO question goes into detail, but variables don't persist across reloads.
If you're staying within the same domain (e.g. everything happens at https://example.com, so https://example.com/page1, https://example.com/page2, etc.) then you can use cookies or local storage to keep track of values.
You can't keep track of functions easily with local storage or cookies.
Cookies and local storage are not available across domains.
I would use local storage as that is easier to interface with. So instead of:
var someVar = 'hello';
Write
localStorage['someVar'] = 'hello';
Then to use the variable:
console.log(localStorage['someVar']);
Local storage has a maximum size of 10MB. Probably enough for any automation script.
If you want to persist functions across page reloads, you should use something like grease monkey to store your user scripts.

JavaScript clean memory

I have a problem about memory management.
My simpliest code is here:
var url="/abrapo.php";
var ob={start_:100, token:null}
function post_token(){
$.post(url,{access:ob.token})
.done(function(data){
console.log(data);
ob=data;
});
}
I call function post_token every seconds. So after 2000 call user has problem of memory, ram goes up to 2GB. I don't need to save anything just want to log data after post and clear memory. I've already googled and find delete ob. But it does not clean the memory. What increase memory and how can I clean it without reloading the page
Use your browser's profiling tools to determine where you're accumulating memory. In Chrome these profiling tools are located under the Performance tab in the Chrome Developer Tools F12.
Click the Memory checkbox near the top to enable memory profiling
Click Start Profiling and Reload Page (Ctrl+Shift+E)
Let the profiling run for a while, most pages load in 2-3 seconds but it sounds like your page needs to run longer than that
Click the Stop button to halt the profiling
Among all the other performance graphs, you should see one for memory usage that looks something like this.
You can use this to see if, and when, the browser is performing garbage collections on the Javascript heap. You may need to manually clear certain objects by setting them to null. Also, try to avoid cyclical references and other complex referencing patterns that could cause the javascript engine to hold on to objects longer than it has to.
Click here, for more about the memory management and garbage collection in the browser.
I had similar problems while writing UI for a data acquisition device and managed to make it fly by setting every variable containing large data arrays to null whenever not used.
Your use case isn't easy to replicate with just your code, but I suggest you try setting
data = null;
and
ob = null;
whenever not in use.
You might have to tweak suggestion a bit, say by assigning only token:
ob.token = data.token;
in such case only token would have to be set to null
ob.token = null;
What this achieves essentially is that it gives garbage collector a chance to clear unused objects since variables using those were clearly set to null. Oh, yes, and memory profiling is your friend to find out what exactly should you null
According to your code example, the problem is with console.log(data)
it make your object accessible from Console. The Garbage collection will free memory only when the object is no more accessible.

Why browser becomes slow with large number o DOM elements

I know this question sounds very trivial, but I just want to know how 'browser processes DOM and what makes it become slow with large number of DOM elements? Is this just about the size? What if DOM elements are not high in number but javascript objects are? Would it still respond slow?
I guess, if there are events attached to javascript objects and we don't dispose them, it responds slow because it has to execute all the event handlers (in a sequential manner), but other than that what are the other reason where 'memory leak' slows down the browser? (Assuming browser has consumed lots of memory but enough memory is still usable in system).
Update:
Surprisingly, CPU and memory usage is always under control while browser responds slow.
If a page is loaded with all its elements and it doesn't change, then there is no reason why it should be slow no matter the amount of DOM elements. However, if you have a dynamic page, there are loads of operations that cause the entire layout to redraw itself. This is called layout thrashing and can have dramatic effects on performance.
The most obvious is that your browser consumps all your memory and when it comes time to render something during scrolling, for example it has no more memory.
If there are no memory issues, then JohanP is write - there is no reasons.
Why do browsers slow down when loading a lot of data? Because they have to load a lot of data. Large images are obviously the worst culprit in terms of load speed, but page load is directly correlated to the number of kilobytes being transmitted. If you have a lot of code, it's going to have a large filesize.
As for JavaScript, there are four main causes of leaks:
Accidental Global Variables -- Variables not explicitly defined will assume a global scope:
function foo(arg) {
bar = "This is a global variable";
}
Forgotten Timers Or Callbacks -- When declaring a variable in a timed function like setInterval(function() {}), the variable still exists at the end of the interval.
Out Of DOM References -- When assigning reference to an element, which later is removed, the reference still exists:
var button: document.getElementById('button');
document.body.removeChild(document.getElementById('button'));
Closures -- Loops often don't get closed 'correctly', losing variable scope, and leaking in the process. See JavaScript closures.
See 4 Types of Memory Leaks in JavaScript and How to Get Rid Of Them for further information on JavaScript memory leaks.
Hope this helps!

Is it possible to detect page modification through userscripts? [duplicate]

This question already has answers here:
Can a website know if I am running a userscript?
(2 answers)
Closed 9 years ago.
If you have a website, can you somehow find out if visitors are modifying your site with javascript userscripts?
In short: EEEEEEK! Don't do it! Rather, decide what needs to be guarded, and guard that. Avoid polling (periodical checking) at all costs. Especially, avoid periodical heavy checks of anything.
Not every change is possible to track. Most changes are just extremely hard to track, since there are so many things that could change.
Changes to the DOM (new nodes, removed nodes, changed attributes) can be detected. The other answer suggests checking innerHTML periodically, but it's better to use mutation observers (supported by Firefox, Chrome) or the older mutation events (DOMSubtreeModified et al.) (support varies by event) instead.
Changes to standard methods cannot be reliably detected, except by comparing every single method and property manually (eeeek). This includes the need to reference tons of objects including, say, Array.prototype.splice (and Array and Array.prototype as well, of course), and run a heavy script periodically. However, this is not what a userscript typically does.
The state of an input is a property, not an attribute. This means that the document HTML won't change. If the state is changed by a script, the change event won't fire either. Again, the only solution is to poll every single input manually (eeek).
There is no reliable way to detect if an event handler has been attached. For starters, you would need to guard the onX attributes (paragraph #2), detect any call to addEventListener (ek) (without tripping the paragraph #2 check), detect any calls to the respective methods by your library (jQuery.bind and several others).
One thing that plays in your favor, and possibly the only one: user scripts run on page load (never sooner), so you have plenty of time to prepare your defenses. not even that plays in your favor (thanks Brock Adams for noting and the link)
You can detect a standard method has been called by replacing it with your own (ek). There are many methods that you would need to instrument this way (eek), some by the browser, some by your framework. The fact that IE (and even firefox can be instructed to, thanks #Brock) won't let you touch the prototypes of the DOM classes adds another "e" or two to the "eek". The fact that some methods can only be obtained via a method call (return value, callback arguments) adds another "e" or two, for a total of "eeeek". The idea of crawling across the entirety of window will be foiled by security exceptions and uncatchable security exceptions. That is, unless you don't use iFrames and you are not within an iFrame.
Even if you detect every method call, DOM can be changed by writing to innerHTML. Firefox and Chrome support Mutation Observers, so you can use these.
Even if you detect every method call to a pre-existing method and listen to mutations, most properties are reflected by neither, so you need to watch all properties of every object as well. Pray someone does not add a non-enumerable property with a key you would never guess. Incidentally, this will catch DOM mutations as well. In ES6, it will be possible to observe an object's property set. I'm not sure if you can attach a setter to an existing object property in ES5 (while adhering to ES3 syntax). Polling every property is eeeek.
Of course, you should allow your own scripts to do some changes. The work flow would be to set a flag (not accessible from the global scope!) "I'm legit", do your job, and clear the flag - remember to flank all your callbacks as well. The method observers will then check the flag is set. The property watchdogs will have a harder time detecting if a change is valid, but they could be notified from the script of every legit change (manually; again make sure the userscripts cannot see that notification stream). Eeek.
There's an entirely different problem that I didn't realise at first: Userscripts run at page load, but they can create an iFrame as well. It's not entirely inconcievable (but still unlikely now) that a userscript would: 1) detect your script blocker, 2) nuke the page from the orbit (you can't prevent document.body.innerHTML =, at least not without heavily tampering with document.body), 3) insert a single iframe with the original URL (prevent double loads server-side?) and 4) have a plenty of time to act on that empty iframe before your protection is even loaded.
Also, see the duplicate found by Brock Adams, which shows several other checks that I didn't think of that should be done.
If you don't have script yourself that changes things you cold compare document.body.innerHTML and document.head.innerHTL with what it was.
When you do change DOM in your script you can update the values to compare it with. Use setInterval to compare periodically.

Javascript: how to really prove a frame is loaded? Global variables not working?

I've been fooling around with developing an IETMs interface (Interactive Electronic Technical Manual - like an interactive parts catalogue) to display the data live from an existing Access database. The idea is to be able to run this interface on a network hosted intranet with straight HTML, plain Javascript, VBScript & ActiveX objects, so that it doesn't require IIS etc to run ASP or PHP etc (I don't want to involve corporate IT for the IIS).
All is going pretty well, & I'm impressed with the setup except for a few minor things - checking if a frame is loaded, & global variables.
My setup is a HTML page hosting 5 frames with each containing an empty (which gets the page written to it dynamically), but I need to ensure all frames are loaded before getting into the heavy stuff (which Javascript is handling brilliantly!). But I'm finding that Javascript sux at truly detecting if a frame is loaded (someone please prove me wrong!). I have all 5 frames call a function fnInitialiseIfReady(), then if I could either successfully test if all frames are loaded, or if I could globally count if this function has been called 5 times, I can proceed with confidence & call my function fnInitialise(). But unfortunately neither is working for me. :(
From tireless internet searches, I've tried the 'frames always load in order' theory, & that is simply not correct. I have set up a test with the frames calling a function passing their name as a parameter, & each time the frames load in a different order every time. It is totally random. Note: I proved this by having the first 4 frames call a certain function(which contains an alert() line showing the frame name parameter passed), & having the last frame call a different function (which contains an alert("all are loaded!") line). The "all are loaded!" does not always appear last.
I've also tried the '.frames["FrameName"].document.loaded' approach, & it ALWAYS returns 'undefined' for every frame. Am I doing something wrong here?
I've also tried the '.frames["FrameName"].window.location.href' approach & it ALWAYS returns the html filename regardless of whether that page has loaded or not, so it is not an indicator of loading completion.
I've also tried the '.frames["FrameName"].document.location' approach & it's ALWAYS the same as the '.window.location.href' approach.
Also, I'm finding Javascript will not hold global variables for me at all. I don't know if it's a combination of multiple frames & using Javascript & VBScript together, but global variables just do not hold a value at all. Local variables (within functions) are fine. Any ideas? I don't have many globals, so I'm thinking of using a cookie. A valid Solution?
BTW, the reason for also using VBScript is that it accesses the ActiveX controls by default, & being a corporate intranet app I can guarantee MSIE usage.
It's frustrating because if I can solve these 2 relatively minor issues, then I'm super impressed with the robustness of this Javascript/VBScript approach. By leveraging each of their strengths, it's crunching the data just as quickly as the VB, C#, & C++ programs I've written for this particular dataset. I'm impressed! :)
Thanks in advance,
Dave Lock.
AFAIK, each frame (window) has its own 'global' context. That's why your Javascript objects can't see each other without special effort.
Are the frames nested? If not (i.e. they're all in the same frameset), you could try to add an onload event handler for each, and have those refer to some central global object.
I'm thinking you might have to add those onload event handlers from code (using attachEvent), so that you could assign the same event handler to all frames. Otherwise, I think each onload would run within its own (window's) global context.

Categories

Resources