jQuery .getJSON() poll memory leak - javascript

I have a dashboard that presents some stats and until now it was quite static, i.e. if I wanted a fresh data I had to refresh the page. I have since moved to a more dynamic way with jquery to load stats on an interval. It works pretty good, I don't need to refresh the page anymore.
However, I noticed that if I leave the page open for some time the memory usage goes up and up with no signs of stopping.
It starts at about 50MB then in couple of hours (maybe only 1) saw it reach 1.2GB. Refreshing the page doesn't reclaim the memory!
And the obvious question... What am I doing wrong?
Samples:
#app.route("/getstats")
def getstats():
return jsonify({'data': render_template('stats.html', stats=stats())})
<script type="text/javascript">
$(function poll() {
var isMenuClosed = document.querySelector('.mdl-menu__container.is-visible') == null;
if (isMenuClosed) {
$.getJSON('/getstats',
function(data) {
$("tbody#stats").empty().append(data.data);
componentHandler.upgradeDom();
});
$.getJSON('/getwidgets',
function(wdata) {
$("div#widgets").empty().append(wdata.data);
});
}
setTimeout(poll,5000);
return false;
});
</script>
I have very limited knowledge on Python and especially JavaScript.

Related

GC causing brief browser freeze; memory leak?

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);
});
}
});

Ensure Ionic Angular UI has redrawn before kicking off processor intensive task

I have an angular app within the ionic framework which has an encrypted database. The step of opening the database is an intensive task. (up to 6000ms on a typical device).
I have a Login button on the page which sets a flag in the controller "Data.Loading = true".
Within the on-page ng-template there is a block
<div ng-show="Data.Loading">Please Wait</div>
The code which "logs in" is as follows:
$scope.Login = function() {
if ($scope.IsCorrect($scope.Data.Password)) {
$scope.Data.Loading = true;
$scope.OpenAndContinue();
}
}
$scope.OpenAndContinue = function(){
MyDatabase.open().then(function() {
$scope.Data.Loading = false;
$rootScope.Display.Menu = true;
$ionicHistory.nextViewOptions({
disableAnimate: true,
disableBack: true,
historyRoot: true
});
$state.go("app.home")
})
}
The problem with the above is that the UI is NOT particularly responsive. On this page. In fact it is downright slow - especially compared to numerous other buttons within the app.
The view takes a second or two to update and say "please wait" then another couple seconds to actually finish opening the database.
If I accept that the core-function of opening an encrypted database is sufficiently complex as to prevent opening quickly, I would at the very least like the view to respond to a user's tap instantly in order to let them know
that the thing isn't broken.
I have tried a number of different published angular fixes.
$scope.Login = function() {
if ($scope.IsCorrect($scope.Data.Password)) {
$scope.Data.Loading = true;
$timeout($scope.OpenAndContinue);
//$timeout($scope.OpenAndContinue, 0, false);
//$timeout($scope.OpenAndContinue, 250, false);
}
}
$scope.Login = function() {
if ($scope.IsCorrect($scope.Data.Password)) {
$scope.Data.Loading = true;
$scope.$evalAsync($scope.OpenAndContinue);
}
}
$scope.Login = function() {
if ($scope.IsCorrect($scope.Data.Password)) {
$scope.Data.Loading = true;
$ionicModal.fromTemplateUrl("templates/modals/login.html", {
scope: $scope,
animation: 'scale-in',
backdropClickToClose: false,
hardwareBackButtonClose: false
})
.then($scope.OpenAndContinue);
}
}
Nothing I've tried so far gives the "responsiveness" that I'd expect from a button tap. Nor the snappiness I've seen elsewhere in the APP.
Is there anything else I can do to make sure the login feels "snappy"?
Even the modal doesn't have that "snap" feeling.
Sadly - it seems that the answer was unobtainable based on the information I gave.
The function $scope.IsCorrect contained a call to another function $rootScope.$broadcast('myapp.login')
There was an event listener elsewhere in the APP that opened the database itself (thereby doubling processor usage in those few milliseconds and running before the $apply() updates as handled in the code above.)
I eventually found the additional call to "opendatabase" by adding a console.trace() command to the code that opened the database. This allowed me to see a full stack trace at that point in time, and determine that something else was causing the performance problem.
StackOverflow penalizes users for deleting questions, so I've decided not to kill this Q&A - hopefully someone can find something useful in this.

How to prevent Chrome and Firefox from consuming vast amounts of memory over long periods of time?

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

Simple function using a lot of memory

I'm using local storage because after the click, the page reloads, so I can keep track of the last item clicked.
As you can see, I've tried to clear localStorage in order to shrink the memory in use, but it's already at 1.000.000K in less then 10 minutes of usage.
Is this script redeclaring this variables at different location everytime my page reloads?
What is happening that is making it use so mant memory?
This is my entire code.
It's an extension I'm creating for chrome, it selects an option and clicks the button, the button submits a form, the page reload, and it does eveything again and again.
var last = localStorage.getItem('last');
var current = getNext(last);
var prox = getNext(current);
localStorage.clear();
$('select[name="myselect"] option').each(function(){
if($(this).val().indexOf(current)>-1){
$(this).prop('selected', true);
$('.abc').first().click();
localStorage.setItem('last',current);
}
});
function getNext(current){
var arrIds = ['227','228','229','230','231','232'];
return arrIds[arrIds.indexOf(current)+1] || '227';
}
Updated code, without var declarations, that has decreased memory consumption drastically, but with time, the memory raises (in ten minutes went from 160.000K to 240.000K):
$('select[name="myselect"] option').each(function(){
if($(this).val().indexOf(getNext(localStorage.getItem('last')))>-1){
$(this).prop('selected', true);
$('.abc').first().click();
localStorage.setItem('last',getNext(localStorage.getItem('last')));
}
});
function getNext(current){
var arrIds = ['227','228','229','230','231','232'];
return arrIds[arrIds.indexOf(current)+1] || '227';
}
As per the discussion in the comments below the question, the issue appears to come from jQuery itself. The exact reason isn't known at this point, but it appears jQuery has retained data that is not being released when the form is submitted.
This probably has to do in part with some aspect of it being a Chrome extension, since typically on a refresh, the browser would release all memory including globals.
jQuery creates great potential for memory leaks by holding data and closures in a global reference called jQuery.cache. If this is not cleaned up properly, leaks abound.
Since you're creating a Chrome extension, there shouldn't be much to compel you to use jQuery, since you'll not need to worry about browser incompatibility from browsers like IE6 and 7. By using the DOM API directly without such dependencies, the overall code will be smaller and much faster.

poll ASP application variables in javascript

I have the code below to poll application variables in ASP. The code below works the first time meaning when I first start the page, if the Application("NFC")= 1 , The IF statement in the setinterval function will catch it, display the alert and then reload the page. The issue is now that the page is running, if another page sets the Application variable back to 1 again, the if statement below will no longer trigger. If I refresh the page manually, it will work again once.
I placed in the Head and the Body and the same results.
Does anyone know why this is happening and what I can do to get this working?
This code is to minimize accessing a database. I am currently accessing the database every 20 seconds now and this will allow me to only access the database if the application variable has changed, polling the variable every 5 seconds.
Any help is greatly appreciated.
Thank you JOHN...
<%
If request.querystring("R") = "reset" then
Application("NFC") = 0
response.redirect("test2.asp")
end if
%>
<script type="text/javascript">
setInterval(function(){
if('<%= Application("NFC")%>'== '1'){
alert('NFC has changed. This alert is for testing and is not needed in final code');
self.location='test2.asp?R=reset';
}
}, 5000);
</script>
basically any ajax routine will do, jQuery is more robust than this modern browser example:
server.asp:
<%= Application("NFC")%>
client.js:
function aGet(turl, callback) {
var XHRt = new XMLHttpRequest();
XHRt.onload= callback;
XHRt.open("GET", turl, true);
XHRt.send("");
}
aGet("server.asp", function(e){
alert(e.target.responseText);
});
once you see how, it's simple, but it's hard to search for. that's got to be about the simplest back-end code ever...
kudos on using the under-used yet awesome RAM cache that is the Application object: if used correctly, it can enable great real-time apps dues to the negligible cost of pinging that simple server page.

Categories