Closed Bug 1110554 Opened 10 years ago Closed 3 years ago

Tabs evicted under memory pressure are reloaded from network, with data loss

Categories

(Firefox for Android Graveyard :: General, defect)

34 Branch
All
Android
defect
Not set
normal

Tracking

(Not tracked)

RESOLVED INCOMPLETE

People

(Reporter: yumpusamongus, Unassigned)

References

Details

User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:34.0) Gecko/20100101 Firefox/34.0
Build ID: 20141201111703

Steps to reproduce:

1. Load a few tabs (say, 4-8) in Firefox for Android.

2. Switch to each of them to make sure they're loaded.

3. Stay on a single tab for about 10 minutes, so the others get evicted from memory.

4. Switch to one of the other tabs.


Actual results:

Page content is downloaded from the network, often taking 5 seconds or more.  Scroll position is lost.  Form contents are lost.  Changes to the page made with javascript, such as infinite scroll or expanded reddit comments, are lost.


Expected results:

Page content is restored from disk, taking a few hundred ms at most.  Scroll position, form contents, and JS changes are preserved.
I could not reproduce this on my Nexus 5 (Android 5.0), but I assume this happens on memory pressure on different devices. We should not be hitting the network when we shouldn't have to. What do we cache?
My device (GSM Galaxy Nexus) only has about 700 MiB after graphics and misc accelerator reservations, and a considerable part of that is used by Android cruft and background apps. Your 2 GiB device probably ends up with several times as much memory available for Firefox, so it should handle several times as many tabs before it hits the wall. Perhaps try the same test with 25 tabs.

I wouldn't really call the solution to this problem "caching" in the usual sense. It is perhaps similar to the bfcache, but a "cache miss" when switching tabs is incorrect behavior, not a minor performance hiccup. What Firefox ought to do is pickle background tabs under memory pressure and unpickle them when they are accessed again. From the perspective of the web server and any javascript running on the page, a tab being evicted and restored some time later should look exactly like a desktop user putting their machine to sleep and waking it some time later.

All the state needs to be preserved, and I mean *all* the state.  Viewport zoom and location, form contents, javascript execution state, audio/video playback position, all of it.
See my note in Bug 1106827 Comment 9. Tab content (an amorphous concept, I know) should be the last thing we kick out of memory, not the first.
Status: UNCONFIRMED → NEW
Depends on: 1106827
Ever confirmed: true
OS: Linux → Android
Hardware: x86_64 → All
Reducing own memory footprint and being less eager to drop content would reduce the impact of this issue, but isn't that just pushing the problem back so it happens at 12 tabs instead of 6? The problem isn't the existence of memory pressure.  The problem is that FF does not react gracefully to it.

Aside from acts-of-OOM-killer, no amount of memory pressure should cause state loss, and memory pressure should never cause anything to be re-downloaded from the network.
(In reply to Russell Haley from comment #4)

> Aside from acts-of-OOM-killer, no amount of memory pressure should cause
> state loss, and memory pressure should never cause anything to be
> re-downloaded from the network.

My assertion in Bug 1106827 is that we should preserve page state *in memory* under memory pressure as far as possible.

That's the opposite of what Fennec does now: right now Fennec assumes that it'll be able to reload zombie tabs from the network (albeit with much of the content already cached).

If, as you say, we can move that limit from 6 to 12 tabs, we make another big slice of users pretty happy. Most people use a handful of tabs.


To always be able to restore state for an arbitrary number of tabs, as you describe, we'd need to persist form data, session state, the DOM itself, images that were downloaded via XHR, data that we were explicitly told not to cache by the server... even the JS heap has to be maintained in order to restore a page that was swapped out.

Those things are potentially huge. Low-memory devices often have little storage; do you really want to burn a few megs of your very limited storage to write yet another copy of JQuery? And what do we do when Android throws a storage pressure event or deletes that cache? Back to square one.

More importantly, these mechanisms do not exist. We have bits of them -- session store will do form data and scroll position, and we have the network cache -- but not all.

At the extreme, you're asking us to run each page in a virtual machine that can be paused and restarted arbitrarily. That's a huge undertaking, and one that's not well suited to running on a resource-constrained device.


In short: is it worth building an incredibly complicated and expensive pickling solution, when it'll only degrade the experience for the majority of users?

I don't think it is, so we're pursuing more persistence in session store (e.g., Bug 1017927) and memory handling and footprint improvements (Bug 933814).
>To always be able to restore state for an arbitrary number of tabs, as you describe, we'd need to persist form data, session state, the DOM itself, images that were downloaded via XHR, data that we were explicitly told not to cache by the server... even the JS heap has to be maintained in order to restore a page that was swapped out.

Whatever the bfcache is already doing seems to be enough.

>Those things are potentially huge. Low-memory devices often have little storage; do you really want to burn a few megs of your very limited storage to write yet another copy of JQuery? And what do we do when Android throws a storage pressure event or deletes that cache? Back to square one.

My device could be considered "low memory" (only 693 MiB total in settings/apps), and it has 16 GB of flash.  That's enough to push the problem out quite a bit farther.  And the state cache could be compressed, of course.

>At the extreme, you're asking us to run each page in a virtual machine that can be paused and restarted arbitrarily. That's a huge undertaking, and one that's not well suited to running on a resource-constrained device.

On the contrary, it is very well suited to a resource constrained device.  Yes, it would probably use more resources per page. But you would only ever need enough resources to run one page at a time. If you have more resources than you need, you could keep the most recently hit tabs loaded (but paused, to keep Web 2.0 BS JS from wasting battery). That way, low-end devices get greatly reduced data loss, and high-end devices get near-zero data loss and low tab-switch latency.

And once you have the infrastructure in place to do this, it can be used on desktop as well. Reading a pickled tab could be a single contiguous disk read, so it wouldn't be slow on spinny disks. You could have an *actually scalable* web browser.  Imagine 4 tabs to 4000 tabs in a 600 MiB memory footprint, and no CPU activity in the absence of user input.
We have completed our launch of our new Firefox on Android. The development of the new versions use GitHub for issue tracking. If the bug report still reproduces in a current version of [Firefox on Android nightly](https://play.google.com/store/apps/details?id=org.mozilla.fenix) an issue can be reported at the [Fenix GitHub project](https://github.com/mozilla-mobile/fenix/). If you want to discuss your report please use [Mozilla's chat](https://wiki.mozilla.org/Matrix#Connect_to_Matrix) server https://chat.mozilla.org and join the [#fenix](https://chat.mozilla.org/#/room/#fenix:mozilla.org) channel.
Status: NEW → RESOLVED
Closed: 3 years ago
Resolution: --- → INCOMPLETE
Product: Firefox for Android → Firefox for Android Graveyard
You need to log in before you can comment on or make changes to this bug.