How to get a similar behavior between the Garbage Collection of a Single-Page Application and a Multiple-Page Application?

Asked

Viewed 439 times

37

I’ve been doing a lot of research on the web and in stackoverflow communities, and I’m getting to the point of believing that Spas take almost no advantage of the GC algorithm of current browsers.

Our development team was concerned with destroying useless objects in state transitions that could be causing some memory-Leak,removing listeners, events linked to destroyed Doms and all the possibilities we found on the internet. But it still has a kind of memory-Leak on our SPA platform, which can be used for several hours continuously. The chart below represents the memory usage in 2 hours of SPA navigation :

2 hours of SPA navigation graph

It was a 40mb jump to 700mb in two hours. Obviously, there are actually some features like maps and graphs that justify the high memory consumption, but even returning to simpler tasks, the memory remains there for a long time until the GC comes and removes the unused memory.

There is something beyond the things I listed above that can improve GC in a single-page application?

We know that GC cannot be controlled by the client (javascript), although there are some events that trigger this condition. Some user actions such as: navigation, page exchange, window closing and tabs, among others, which in some cases do not happen in a SPA.

How can I get a satisfactory result with memory management in a SPA and I don’t have as many "triggers" for GC activation as in a multi-page application?

  • 6

    Very interesting question (+1) and which was/is the subject of much discussion on the Internet. Many of the improvements were made in the libraries, I remember that Backbone.js had many problems and then corrected them. Which library do you have this problem with? are up-to-date regarding versions? Does this problem happen in all browsers or is it specific to one or the other? what is the type of logic in the application? many instances created? upload external files? dependencies etc... all this would be interesting to know.

  • @Sergio We used Angularjs, I’ve looked at the issues on their github but none that are really relevant. Other than that we have Google Maps and Amcharts. The rest we use Vanillajs(http://vanilla-js.com/) even, making it as simple as possible.

  • 2

    Have you already analyzed dev-tools to see what memory is used and where, and what might be the biggest problem? do you have problems with all browsers? If you refresh the page the problem persists or the browser can get rid of "old memory"?

  • Exactly, we’ve had memory problems before and we’ve learned from mistakes. Today it is "under control", it takes 1 or 2 hours to realize that there are things stuck in memory, which makes debugging by dev-tools difficult, we already identify some points in third party components and report to developers. The point is that even updating the memory remains allocated, and the SPA does not seem to have enough "triggers" to activate the GC, the purpose of my question, among others, is to confirm or deny this thesis.

  • 4

    One idea for debug is to run google Chrome with the flag --js-flags="--expose-gc" what makes the function window.gc that forces the Telescope to rotate. If you run and the amount of memory used remains high it is a strong indication that the problem is not the garbage collector but the application leaking memory (which may be the fault of the used libraries).

  • Brunorb, we use this technique also, the result is that yes the memory reduces a lot. But it’s a debug function because there’s no way the average user is using it. GC in SPA follows a problem for the entire community.

  • 1

    You guys are using html5Mode?

  • 1

    @Rafaelbernard yes, no prefix.

  • @Leonancarvalho this behavior is consistent in various browsers, or just with Chrome?

  • @Onosendai, in other browsers the perception is even more aggressive.

  • I talk about behavior, because if I add target="_selfie"' in the links the navigation will occur as if it were an M.P.A., and does not present the problem as in the SPA, but I lose the whole advantage of a SPA.

  • 1

    @Leonancarvalho just as sharing experiences, I had the same problem in an Angularjs application that used D3.js for rendering dendograms. In this particular case it was a Leak problem with the D3.js module that it managed canvas. The problem was resolved and a new compiled version no longer showed this behavior. I was only able to isolate the problem by partially loading the application modules, until I was able to perceive the increased consumption.

  • This reply https://softwareengineering.stackexchange.com/a/307497/269951 (link in English) may be of interest in the production of a canonical response.

  • 1

    This question is very interesting. If there was a question system of the month, I would choose this one!

Show 9 more comments

3 answers

7


(Note: the OP’s own response is a great alternative, even better I would say. = D Be sure to check!)

Refreshes programmed with a Service Worker

Gives refresh every 1 hour, and uses a service worker to serve refresh the page as fast as lightning. If the page is well implemented, with everything clicking in the right order, it won’t even blink.

By breaking down, you can start using the service worker to implement an offline experience for your users. = D

To keep data between refreshes you will need to save all relevant user navigation data just before giving the refresh. In a React application with Redux for example, you could save JSON from the application’s state in a sessionstorage, and reload it when the page reload... if the key is not there, it is because it is not a programmed refresh, so it was the user who gave refresh even, IE, have to maintain the default behavior of F5.

Unfortunately, I searched for compatibility, and today (2017-08-03) you will have to say goodbye to IE, Edge, Safari and Opera Mini.

Also has requirements to use service worker:

  • the page has to be served via HTTPS (or is it just the js of the service worker? I have to test)
  • the MDN page says that FF does not run service worker in anonymous mode

Refreshes in the background

Another idea is to try to infer the level of activity of the user, or the activities he is doing to find the best time to refresh. For example:

  • prevent refresh if user is typing
  • prevent refresh if there is text selected on the screen
  • etc..

It could still allow refresh only if the page is not active: window.onfocus and window.onblur.

You can combine this idea with the service worker idea too, to speed up the process.

  • We have already used the service worker in this application to implement the offline experience. The idea is good and it can work. Since the service worker works for the entire domain, it may be possible to update all the pages at the same time and thus free up the memory accumulated in the limbos. Perhaps it is only necessary to change after a while the attribute target of the links to self and this way in the next navigation a Full Load happens within the expectations of the user control, since a refresh during use would be a bad experience for the user.

  • Yes, during use the user will end up noticing, however much one tries to keep selected texts, and the state as faithful as possible. So the second idea of refreshing when the user is in another tab, or when the user is quiet for a long time, something like that. This idea of making links once in a while a full load also looks promising. = D

  • By making target="_self" I obtained a similar and more compatible result with the browsers "Legados" https://answall.com/a/226540/7130 But it served more specifically the Angularjs and in theory the React . The serviceworker would be something more idependente framework, so it’s still my favorite answer :)

5

Refreshs after some programmable trigger.

The big problem with the SPA is that it never actually updates the document, the changes are made in memory in a virtual way. It is common for programmers to develop code and not worry about the memory dump, and as a consequence can cause memory Leaks, such as that function executed in a given state "sequester" the memory indefinitely.

Although the target="_self" default browser behavior is to open a link in the same window as an iframe with frame or Frameset /window. Like the tags frame and frameset are obsolete in HTML5 no longer use the target="_self" for this purpose, it now forces a link to open in a new document in the same window. Thus forcing the full page load, recreating all instances and all variables.

In the SPA this behavior is ignored, and it presents an interesting behavior that is to force the Reload when navigating through a state link or virtual navigation, I’m not sure about the correct technical terms. Therefore, within the current frameworks it is possible to measure the time that the SPA navigation is taking place and this then trigger a trigger that will cause the next navigation to occur renewing the document. Below I created a simple javascript function that changes target within some conditions:

function alteraTarget() {
  var regex = /(^mailto:|^javascript:|#)/g;
  var links = document.querySelectorAll('a');
  var alterados = 0;
  for (var i in links) {
    var a = links[i];
    if (typeof a === "function" || regex.test(a.href) || a.target == "_blank") {
      continue;
    }
    a.target = "_self";
    alterados++
  }
  console.log(alterados, " Links alterados ");
}
<!DOCTYPE html>
<html>

<body>

  <h1>My First Heading</h1>

  <p><a href="mailto:[email protected]"> Não altera </a></p>
  <p><a href="javascript:void(0)"> Não altera </a></p>
  <p><a href="#id-elemento"> Não altera </a></p>
  <p><a href="#"> Não altera </a></p>
  <p><a href="http://google.com" target="_blank"> Não altera </a></p>
  <p><a href="/state"> Altera </a></p>
  <p><a href="!/state2"> Altera </a></p>
  <p><a href="http://google.com"> Altera </a></p>

  <button type="button" onclick="alteraTarget()">Alterar target!</button>
</body>

</html>

The solution is too similar to the proposal by @Miguelangelo, and can even be used in conjunction with the ServiceWorker to promote a better user experience, but can be applied in several situations, such as:

Each framework and project will implement a rule, but the way to simulate this update and that will subsequently clear the memory is with the programmed updates of the state(state) SPA.

3

I’m sorry if I seem ignorant about this topic,

but to have a high wear in mémoria, I believe I must also analyze the way in which all this is being written, I will give an example, using var in javascript you create a global scope variable, so it will occupy more memory, etc. Well vcs obviously know this much better than me. But the point I want to make is: How much memory is being spent to store information regarding the pages.

I used to work with SPA and gnt always tried to store big information on web.

All variables and objects are better treated with the es2015 ie using const and let, so it gets stuck to scope by block or function. even if it uses varinside a block (the use of 'use stritcs' if I’m not mistaken helps tbm), it starts before any code block inside the functions. Anyway, take a look if there’s much varand how you store the larger information, and try to put in web Torage, BUT I BELIEVE IT IS MORE angular problem than your code. just take a look at the source code and you’ll see a lot of what I commented on above. Anyway if I understand the question well, I think it helps, otherwise, I’m sorry ahahha. Hugs and good luck

  • Yes, interesting its placement. We use Strict, very few variables are declared globally. And large data is stored in Storage Sessions. After use by a function the memories allocated in this function are discarded by the correct GC? Even if some instances remained in memory there is nothing to justify this behavior. I can not accept as correct but I will give +1 for your positions

  • 1

    I should have put as comment instead of response kk but anyway, look once I had an overload in the system. In this case gnt used the Asp.NET Webapi , and since iis only supports 10 requests in its pool by default. We found that there was an infinite loop within an ajax call (it was very specific, it wasn’t all the time), which greatly increased the load on top of the api. Once we solved it, we left page 70 to 80% faster (something like that) it’s a very big system, but in the end. It was a loop in ajax.

  • I imagine, but the idea would be to explore ways to get memory usage behavior in non-Reload applications.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.