There are lots of information regarding how to check javascript memory running inside certain page, but I need to check the memory usage of my javascript inputted via console.
I am developing some scripts to work as robot like game assistant, so I put my script under the thread(frame) and triggered by setInterval calls every second. Sample code like following:
var msgList = [];
var msgGenerator = function () {
return "Welcome";
}
var msgInterval = setInterval(function () {
var msg = msgGenerator();
if (!msgList.includes(msg))
msgList.push(msg);
}, 1 * 1000);
Actually the message is very small and in total it will be less than 50. But the memory of such devtool(viewed from task manager of chrome) is increasing.
Even after I execute the following call:
clearInterval(msgInterval);
The memeory of devtool is still increasing.
Can anyone guide me how to get memory snapshot of devtool(javascript running on console)? Or is there any other way to analyze the memory leakage of homemade javascript running on console?
I have tried many ways to get the detail memory usage of devtool but failed. It seems there is no such tool/facility. Anyway, if someone found such tool later, please post in this thread.
However, I find the way to avoid memory usage increase of my script running on console: change the setInterval to setTimeout, and achieve the same effect.
The updated codes as following will not have any memory usage increasing any more.
var msgList = [];
var msgGenerator = function () {
return "Welcome";
}
var msgInterval = 0;
var msgLoop = function () {
var msg = msgGenerator();
if (!msgList.includes(msg))
msgList.push(msg);
msgInterval = setTimeout(msgLoop, 1 * 1000);
};
Hope above message can help someone is struggling to solve the "memory leakage" of console scripts or snippets.
Related
I have more than 20 js files like jQuery etc in my project, when I scroll it gets hung as it loads very lazily. How to find which file creates the problem?
It may be one of several things and without looking at your code I couldn't possibly say what the cause would actually be. You've asked an extremely subjective comment. There's no silver bullet when it comes to debugging and problem solving.
I've always found the Occams Razor approach the most effective.
"When you remove all other options, whatever remains, however unlikely, must be the problem/solution/answer."
Firstly, before you start removing JS files, have you tried doing a full-search of your project for .scroll? There's a high likelihood that there are several functions which run on-scroll which are causing reflows, a common problem which such code.
Once you've assessed your code, you can verify exactly what happens when the code executes using the "Performance" tab in Google Chrome to do this (Learn how to use the Performance Tab here). You can take the appropriate action.
Assuming that your code suffers from the same problem I've encountered in my formative years using jQuery - multiple or problematic on-scroll events - you can de-bounce the ones which can run after scrolling has completed. You can do this by using the following pattern.
Scenario 1:
This would run many times. 'N' times for each scrollwheel drag (dependent on settings - mine is 10) and even more times when using the scrollbar.
function someFunc() {
let someArr = [];
for(var i = 0; i < 1000000; i++ {
someArr.push((i * 2));
}
for(var i = 0; i < someArr.length; i++ {
someArr[i] /= 0.25;
}
}
$(window).on("scroll", function() {
someFunc();
});
Scenario 2:
This would run once after scrolling has finished. Waiting for 200ms before executing to ensure the user has completely finishing scrolling.
function someFunc() {
let someArr = [];
for(var i = 0; i < 1000000; i++ {
someArr.push((i * 2));
}
for(var i = 0; i < someArr.length; i++ {
someArr[i] /= 0.25;
}
}
let debouncedTimeout = null;
$(window).on("scroll", function() {
if (debouncedTimeout) {
clearTimeout(debouncedTimeout);
}
debouncedTimeout = setTimeout(someFunc(), 200);
});
Add a console.log("Check") with numbers (check1, check2) and so on in every file. Check your console in your browser, look in which series they load in console. If it takes a while to load the next log you know its the previous file with the number you logged.
Your console should say everything.
But loading so many js files is bad practice.
Try to fit everything in to one, so in further bckend development can go to an .min.js
But if you keep doing this. The simplest way is to keep track of the funcioncesequences with console.log, so that you evrything works how it is supposed to
:)
How can I find and stop all of setInterval (s) in Angular?
Some setInterval do not created by my program and run in another components or even a jQuery in my web application and I want to stop it!
CORS is not concerned.
If you absolutely need "a" solution, even a bad one, then you can overwrite the setInterval and setTimeout functions, and maintain your own list of assigned interval identifiers. However, a much better solution would be to write your code to deal with the fact that other parts of the libraries and frameworks you use can schedule timeouts and ntervals, instead of forcefully killing them with complete disregard of what was relying on them to run in the first place.
Indiscriminantly killing all timers will break things.
So, with that covered, the terrible solution would be code like this:
(function monitorIntervalsAndTimeouts() {
const timerList = [];
const oldSetInterval = globalThis.setInterval.bind(globalThis);
globalThis.setInterval = function(...args) {
const timerId = oldSetInterval(...args);
timerList.push(timerId);
return timerId;
};
const oldSetTimeout = globalThis.setTimeout.bind(globalThis);
globalThis.setTimeout = function(...args) {
const timerId = oldSetTimeout (...args);
timerList.push(timerId);
return timerId;
};
...
And of course, the corresponding clear functions:
...
const oldClearInterval = globalThis.clearInterval.bind(globalThis);
globalThis.clearInterval = function(timerId) {
const pos = timerList.indexOf(timerId);
if (pos > -1) timerList.splice(pos, 1);
return oldClearInterval(timerId);
};
const oldClearTimeout = globalThis.clearTimeout.bind(globalThis);
globalThis.clearTimeout = function(timerId) {
const pos = timerList.indexOf(timerId);
if (pos > -1) timerList.splice(pos, 1);
return oldClearTimeout(timerId);
};
...
and finally, a "clear all timers" function:
...
// Call this whatever you want.
globalThis.clearAllIntervalsAndTimeouts = function() {
while(timerList.length) {
// clearInterval and clearTimeout are, per the HTML standard,
// the exact same function, just with two names to keep code clean.
oldClearInterval(timerList.shift());
}
};
})();
You then make sure you load this using <script src="./monitor-intervals-and-timeouts.js"></script>, without the async and/or defer keyword, as very first script in your page's <head> element, so that it loads before anything else. And yes: that will block the page parsing while it does that. Or if you're using Node (which this will work fine for, too, because of the use of globalThis), you need to make sure it's the absolute first thing your main entry point imports/requires (depending on whether you're using ESM or CJS code).
Remember: this is the nuclear option. If you use this code, you're using it because you need to run something for local dev work that lets you debug your project, for finding out where timeouts/intervals are getting set and cleared. If you need it for that: go for it. But never, ever use this in production to solve a problem relating to timeouts/intervals used by third party/vendor code. Solve that the right way by actually solving whatever problem your own code has.
I have a ~300 line javascript file that appears to be leaking memory, which periodically causes brief browser freezing due to what I believe is garbage collection.
This is my first attempt at writing JS, so my assumptions are pretty much guesses based on what I've been researching and using Chrome's Timeline and other tools.
Here's a very simplified version that reproduces the problem. I am positive I have other code in the script that's broken, but I think if I can get some pointers of what I may be doing wrong here, I'll be able to apply any changes to the rest of the code.
Can someone please help me understand what I could possibly do different to prevent the problem? If it's relevant, the backend I'm using to pull data from is Perl's Dancer2.
$(document).ready(function(){
var temp_limit = -1;
var humidity_limit = -1;
event_interval();
function event_interval(){
$.get('/get_config/event_display_timer', function(interval){
interval = interval * 1000;
setInterval(display_env, interval);
});
}
function display_env(){
$.get('/fetch_env', function(data){
var json = $.parseJSON(data);
});
}
});
I have a long-polling application written in JS fetching XML files to update a web page. It fetches every 5 seconds and is about 8KB of data. I have had this web page open for about 1 week straight (although computer goes to sleep in evening).
When first opening Chrome it starts at about 33K of my PC's memory. After I left it open for a week, constantly updating while the PC was awake, it was consuming 384K for just one tab. This is a common method that my application will be run (leaving the web page open for very long periods of time).
I feel like I am hindering Chrome's GC or am not doing some specific memory management (or maybe even a memory leak). I don't really know how a memory leak would be achievable in JS.
My app paradigm is very typical, following this endless sequence:
function getXml(file){
return $.get(file);
}
function parseXml(Xml){
return {
someTag : $(Xml).find('someTag').attr('val'),
someOtherTag: $(Xml).find('someOtherTag').attr('val')
}
}
function polling(modules){
var defer = $.Deferred();
function module1(){
var xmlData = getXml('myFile.xml').done(function(xmlData){
var data = parseXml(xmlData);
modules.module1.update(data);
}).fail(function(){
alert('error getting XML');
}).always(function(){
module2();
});
});
function module2(){
var xmlData = getXml('myFile.xml').done(function(xmlData){
var data = parseXml(xmlData);
modules.module2.update(data);
}).fail(function(){
alert('error getting XML');
}).always(function(){
defer.resolve(modules);
});
});
return defer.promise(modules);
}
$(document).on('ready', function(){
var myModules = {
module1 : new Module(),
module2 : new ModuleOtherModule()
}
// Begin polling
var update = null;
polling(myModules).done(function(modules){
update = setInterval(polling.bind(this, modules), 5000);
});
That's the jist of it... Is there some manual memory management I should be doing for apps built like this? Do I need to better management my variables or memory? Or is this just a typical symptom of having a web browser (crome/ff) open for 1-2 weeks?
Thanks
Your code seems ok but You don't posted what happens on method "udpate" inside "modules". Why I said that? Because could be that method who is leaking your app.
I recomender you two things:
Deep into update method and look how are you updating the DOM (be careful if there are a lot of nodes). Check if this content that you are updating could have associated events because if you assign a event listener to a node and then you remove the dom node, your listener still kepts in memory (until javascript garbage collector trash it)
Read this article. It's the best way to find your memory leak: https://developer.chrome.com/devtools/docs/javascript-memory-profiling
I had a page which executes heavy javascript code after loading. To prevent the page from freezing upon loading, I spaced the execution into batches with some "no-execution" time in between (using Timeouts), and things worked well.
Lately, I've had to add additional heavy javascript code which can execute upon client actions, yet these actions can occur even before the original heavy script is done executing. This time, spacing the action won't help, since at the "downtime" of one script the other can run and vice versa, which will cause the browser to freeze.
The problem is actually more complicated as there are multiple such actions, each executing a different heavy script, and each script sort of has a different "priority" as to how fast i'd like it to finish, compared to the other ones.
My question is, what is the common practice in such situations? I tried thinking of a way to solve it, but all I could think of was quite a complex solution which would pretty much be like writing an operating system in javascript - i.e., writing a "manager" code which executes every X time (using an "interrupt"), and chooses which "context to switch to" ( = which job should run right now), etc...
This however sounds pretty complicated to me, and I was hoping there might be other solutions out there. My problem sounds like one which I'd assume many people have stumbled upon before, so even if the only solution is what I suggested, I'd assume someone already wrote it, or there is some library support for this.
Any help would be greatly appreciated. Thank you.
== EDIT ==
by "heavy code", I mean for example the DOM manipulation of a great number of elements.
You will need to think of defining your UI/Problem domain as a set of Asynchronous tasks. Here's some more insight http://alexmaccaw.com/posts/async_ui until I formulate a better answer for you.
If you don't want to block your script you can use web workers. See MDN: Using web workers for a good introduction. Note that web workers are still relative new and not supported by most browser.
However, if you want to support all browser and add some kind of priority for your "heavy scripts", you should define something yourself, e.g:
function WorkerQueue(this_argument){
this.queue = [];
this.this_argument = this_argument;
this.priority = 1;
}
WorkerQueue.prototype.enqueue = function(callback){
this.queue.push(callback);
}
WorkerQueue.prototype.dequeue = function(){
return this.queue.splice(0,1)[0];
}
function WorkerPool(){
this.pool = [];
this.status = "running";
this.timeout = null;
}
WorkerPool.prototype.addWorker = function(this_argument){
this.pool.push(new WorkerQueue(this_argument));
return this.pool[this.pool.length - 1];
}
WorkerPool.prototype.nextTask = function(){
var max_priority = 0;
var max_priority_task = this.pool.length;
for(var i = 0; i < this.pool.length; ++i){
if(this.pool[i].priority > max_priority && this.pool[i].queue.length !== 0){
max_priority = this.pool[i].priority;
max_priority_task = i;
}
}
// pool is empty or all tasks have an invalid priority
if(max_priority_task === this.pool.length)
return;
if(this.pool[max_priority_task].this_argument)
this.pool[max_priority_task].dequeue().apply(this.pool[max_priority_task].this_argument);
else
this.pool[max_priority_task].dequeue().apply();
if(this.status !== "running")
return;
this.timeout = setTimeout(function(t){return function(){t.nextTask();};}(this),1000);
}
var Workers = new WorkerPool();
var worker1 = Workers.addWorker();
worker1.enqueue(function(){
console.log("Hello");
});
worker1.enqueue(function(){
console.log("World");
});
var worker2 = Workers.addWorker();
worker2.priority = 2;
worker2.this_argument = worker2;
worker2.enqueue(function(){
console.log("Worker 2 - changing priority");
this.priority = .2;
});
worker2.enqueue(function(){
console.log("Worker 2 - after change");
});
Workers.nextTask();
Demo
In this case, every "heavy script" is a worker, which is basically a queue of tasks. You create a new worker in the pool by using addWorker and add tasks to the specific workers queue by using worker.enqueue(callback).