Closed Bug 62651 Opened 24 years ago Closed 24 years ago

Put session history on a diet

Categories

(Core :: DOM: Navigation, defect, P2)

defect

Tracking

()

RESOLVED FIXED

People

(Reporter: adamlock, Assigned: radha)

References

Details

(Keywords: memory-footprint)

Attachments

(5 files)

It looks like session history is coming out as a pretty big ticket item in terms of how much memory it's taking up over time. In fact, it's second only to imagelib in terms of how much it's contributing to our process size growth! See these posts, for example: news://news.mozilla.org/3A2EABB5.2060403%40netscape.com news://news.mozilla.org/3A2CAD49.4020303%40netscape.com Essentially, these posts show session history is an unbounded list and grows without limits. In long browsing sessions, the history adds noticeably to the overall memory bloat. A bunch of ideas have been bandied about, including * saving a limited number of URLs in the history * truncating history by visit time, instead of count * multi-level session history (e.g., form state for last n URLs only) * tunable settings via prefs * memory pressure observer - flush when the memory is low * tie-in with session history persistence work
Keywords: footprint
See related bug 62713, which deals with shrinking the size of each nsSHEntry.
*** Bug 62956 has been marked as a duplicate of this bug. ***
nav triage team: p2 nsbeta1.
Keywords: nsbeta1
Priority: P3 → P2
Blocks: 44352
nom 0.8. Two things: 1. session history (and global history for that matter) need to be observers of the memory pressure topic. When they get memory pressure notification, they need to "shrink". A first cut at "shrinking" might be just to zero out. 2. max number of entries should be a pref setting.
Keywords: mozilla0.8
The attached patch has not been built on linux yet.
nsSHistory::~nsSHistory() has wierd indentation. actually the entire patch does. +nsSHistory::PurgeHistory(PRInt32 aEntries) + while (cnt < aEntries) { this smells like a for loop, however due to features of bad c++ compilers i can understand if you don't rewrite it as such. + cnt++; I think ++cnt; is better in c++ because you don't ask strict compilers to save the old value of cnt. + if ( urlBarHist.count == 0 ) if (!urlBarHist.count) + <titledbox orient="vertical"> + <title><text value="&shistory.label;"/></title> odd indentation, and also odd syntax.
Keywords: patch, review
nsSHistory::~nsSHistory releases the globally-held service reference once only, nulling gPrefs, but nsSHistory::nsSHistory gets the service on every constructor call. Doesn't that result in a leak? In any event, holding a service until a destructor is called can be bad at shutdown. Who calls this destructor? timeless is right, the indentation is a mess. Please convince your editor to expand tabs, and follow the Emacs modeline (which says that the indentation unit is two spaces, not 3, 4, or 7 ;-). However, I don't agree with his nit-picking (I pick nits too, that's not the problem): - PRInt32 cnt; for (cnt = 0; cnt < aEntries; cnt++) { ... } is better than the while, and the uninitialized PRInt32 cnt declaration has to go outside the for header, but so what? - cnt++ is no worse than ++cnt for any compiler worth a damn, because the value is discarded. In the case of C++ STL-like iterators, prefix ++ wins even when the value is discarded, but here we are dealing with an int. True, you might just use prefix-++ for all cases where the value is discarded, whether int or operator-overloaded object type. But I think that's a matter of individual taste, so what radha wrote (cnt++;) should stand, whether in a while loop or in the proposed for loop header. - Testing whether an int is non-zero can be done with !, but I think that's not as good a style as one that reserves ! for boolean and pointer operands. A counter brings to mind a number line, not a true/false or invalid address or valid pointer set of values. Again, this is such a small thing that I would not dictate ! over == 0 for integral types. What radha wrote there is fine. Having picked nits on top of nits, we should give the patch a closer look for more substantive problems (although it's not so easy to read without better indentation). /be
- _elementIDs = ["histDay"]; + _elementIDs = ["histDay", "shistMax"]; And as long as your touching this, please declare _elementIDs and kill another strict warning.
errr, you're. + var urlBarHist = nsJSComponentManager.getService ("@mozilla.org/browser/urlbarhistory;1", + "nsIUrlbarHistory"); + if ( urlBarHist ) How often will this fail? Let's remove this check. + { + var button = document.getElementById("ClearUrlBarHistoryButton"); + if ( urlBarHist.count == 0 ) + { + button.setAttribute("disabled","true"); + } + else + { + button.removeAttribute("disabled"); + } + } This can be shortened to button.disabled = urlBarHistory.count == 0; +/* + function onOK() + { + dump("In onOK\n"); I know this is commented out, but please remove these dump()s. We're trying to get rid of all of these kinds of dump()s that fill up the console in release builds. + var SHistory = nsJSComponentManager.getService ("@mozilla.org/browser/shistory;1", + "nsISHistory"); + var button = document.getElementById('shistMax'); + var size = button.value; + if ( SHistory ) Don't need this check. + { + dump("Setting Max SHistory length to " + maxSize); Remove this also, please. + SHistory->SetMaxLength(maxSize); maxSize?? Don't know where that came from, but it's commented out, so...*shrug* Why do we need this onOK function and the commented doSetOKCancel() above it?
I agree strongly with Brendan. >+pref("browser.session_history_max_entries", 9); Also, the default appears to be 9 history objects, no? That seems VERY small to me. The number we limit to is 100, though that's probably high. I'd suggest something more like 40 or 60. IMHO.
Urgh., I realise I added the patch while I was in the middle of debugging with a small pref value (9) and toying with the onOK() method. obviously, I have more work to do on the patch.
IIRC, MozillaClassic pruned history at 50 entries. /be
IIRC that's the limit (50) I saw in 4.x too while testing it's session history...
The latest patch takes care of the following things: 1) Builds on linux 2) History Initial size set to 50 3) I figured what the problem was with the OK callback function in pref-history.xul. So that code has been uncommented and cleaned up 4) Some of the already existing tab problems in nsSHistory.cpp fixed. 5) No need for the pref service to be a global static member. Fixed that part. Works well for the most part. Not sure about the nit-pickers though. Can I get some reviews and super reviews. Thanks,
Status: NEW → ASSIGNED
Please use the simplified button.disabled as outlined in my 01-10 comment. Couple comments on the new patch: + if ( urlBarHist.count == 0 ) Don't pad the condition with spaces, please (not done elsewhere in the same file). How often will retrieval of the nsIUrlbarHistory service fail? If not often, please remove the try/catch. We're trying to cut down on unnecessary dump()s, and in the rare case that this retrieval would fail (unless I'm missing something), an exception would be far more useful than an enduser-readable failure message. + var button = document.getElementById('shistMax'); Why is this variable called `button' if it holds a textfield?
Blocks: 64833
couple suggestions. 1. "browser.sessionhistory_max_entries" - maybe that should be "browser.history.session_max_entries" to delineate the diff between session and global? 2. You retrieve the pref service in the shistory constructor. XPCOM component constructors really shouldn't do more than init the ref count. You should add an init method, which returns an nsresult, to the shistory class and do that work in there so error code can be pushed out if need be. You'll also need to change your factory constructor to reflect the init (http://lxr.mozilla.org/mozilla/source/xpfe/components/shistory/src/nsSHistoryMo dule.cpp#37 -> NS_GENERIC_FACTORY_CONSTRUCTOR_INIT())
Oops, forgot to add the nsSHistoryModule.cpp diffs to the recent patch. It follows
There is no pattern right now in the prefs files in differentiating global history from session Hsitory. I thought browser.history.session_max_entries was little confusing. So, I made the SH pref to browser.sessionhistory.max_entries. May be all SH related prefs in the future can follow this pattern.
Please address my comments as well... Or should I just post a patch that does so (for that file)?
bug 33115 patch 2 is killing ghist.* entries. has anyone ever heard of them?
Blake, I think the try {} .. catch{} is defensive coding and I intend to keep it. I'll probably take the dump() off. Regarding the way the "Clear urlbar history" is disabled, I think what is in there right now is more easy to understand than the suggestion you made. I'll probably do these changes before I checkin. I may not necessarily attach a patch for these. I don't think pruning of ghist.* prefs from all.js has any impact on this bug or the patch attached here.
Should the session history be listening for changes to the preference if we intend for the user to be able to change it at runtime? Is it also possible to check the user-supplied value so that stupid values such as -1000 are rejected?
Forget the first issue, the code in onHistoryOK should cover that... The second question still stands though.
On the second question, I can add code to nsSHistory::SetMaxSize() to ignore such values, programatically. But should we also provide UI feedback in the pref panel for such values? Should there be a max limit too? What if the user typed 10000? Should there be a enforced limit of 50? ie., user can not enter a value beyond 50?
Though I have not received any formal "r=" and sr=" comments in this bug, I have received several suggestions on the patch and I have incorporated most of them to the extent possible. The patch has been around for about 6 days and I think the performance team would like to use it in their daily perf tests. So, I intent to checkin what I have unless anybody has major objections to it.
radha: could you please post the latest patch that you intend to check in?
Only one nitpicky comment: - In nsSHistory::Init(), don't use `bare' nsServiceManager. Instead, use scc's newer form with a ContractID: nsCOMPtr<nsIPref> prefs = do_GetService(NS_PREF_CONTRACTID); if (prefs) { ... } Fix that, and sr=waterson. Somebody more familiar with session history (law? alecf?) should r= one more time, too. thanks!
radha: the try {...} catch (ex) {} (empty catch) usage may be the wrong thing, as blake tried to point out. It's not defensive, if the errors it ignores lead to further badness that isn't well-handled, and/or if the errors it ignores are not reported to someone who can repair things. For example, in Startup, if the service isn't available, shouldn't the exception propagate all the way to the native code? Also, blake pointed out a better way to write + if (urlBarHist.count == 0) + { + button.setAttribute("disabled","true"); + } + else + { + button.removeAttribute("disabled"); + } IIRC, he suggested button.disabled = (urlBarHist.count == 0) -- does that not work? If it does, please use it. Otherwise, can someone school me on why one must *remove* an attribute to (re-)enable an input element? /be
r=law "cvs diff -w" would have helped in this case, BTW. One thing that threw me for a moment was the fact that you added a maxLength attribute to the interface but each instance actually shares a single, global attribute. I wanted to think that each SH object had it's own max length. Not much you can do about that, I suppose. nsISHistory isn't a service, is it? There's a unique instance per browser window, right? It seems odd for a random instance to be created by the pref-panel just to get an object to call SetMaxLength through. I guess that's the flip side to making that a per-instance attribute when really it's not. Would a pref change callback be better?
There look to be a couple of sloppy button rules (cd mozilla/themes ; find . -name \*.css -print | xargs grep -n disabled) that simply test for presence of the attribute (`button[disabled]') instead of testing for attribute and value (`button[disabled="true"]'). Radha: are you dealing with one of these rules?
be: Can you suggest a way to get a handle to a service/object and use it safely with out assuming that the creation call would have succeeded. I understand that., var SHistory = nsJSComponentManager.getService(.....); if (SHistory) {.....} isn't the best thing to do either. Sometime ago, removeAttribute() was the way to disable a attribute rather than test for its value. That has changed. I don't believe there is anything wrong with blake's suggestion.
Assuming that it succeeded is probably the best way to go, unless there's reasonable probability that it will fail. After all, an exception is far more useful than a human-readable "***couldn't retrieve service" failure. In this case, I can't think of any reason why the nsIUrlBarHistory interface would frequently be unavailable. The debate about whether to remove attributes or just negate them has been going on for awhile, but I don't think a definitive conclusion was ever reached. Some people argue that the attribute should be removed entirely, because it's only an attribute of the element if it's true. Others argue that the negated attribute, e.g. NOT being hidden, is also a property of the element. Nowadays, I think we generally prefer removing the attribute instead of setting false, although we still do the latter (inconsistently) in many places, which is often dangerous. XBL-defined properties supercede the need for this debate and make attributes easier to read and modify. "disabled" is a <property/> of the textfield binding, so it can be accessed directly (button.disabled instead of button.set/getAttribute()). It's typically just a form of shorthand, though, since the property [s/g]etters usually just call set/getAttribute. So accessing the attribute directly if it's defined in XBL is almost always preferable to using set/getAttribute.
The last patch, with the pref set to `8', plus the patch for bug 65908, reduce the gross VM growth rate with the lea-pre7 allocator from 10.1KB/URL to 5.8KB/URL. After loading 500 pages, that's a savings of about 2MB of virtual memory footprint. Nice going!
I checked in the latest patch with little more nit-pick comments taken care of. Shall try to address some of the pref UI improvements(like ensuring illegal values are not saved in prefs)in a later checkin.
Status: ASSIGNED → RESOLVED
Closed: 24 years ago
Resolution: --- → FIXED
whoo! hoooo! thanks for working on this radha. sounds like it's going to make a big difference in memory usage.
The fix for this bug adds an additional dependency upon prefs from shistory. Module dep tracking for http://bugzilla.mozilla.org/show_bug.cgi?id=59454.
Keywords: mozilla0.8
No longer blocks: 64833
why is this pref in the UI? there is absolutely no reason for it, no end user will ever need to change it, and it is yet another reason why our prefs UI is bloated and confusing. was there any feedback from UE on adding the pref UI?
This was put in because it was part of what was causing long-term heap fragmentation (and footprint growth). The newsgroup discussions referenced provide some of the background. Netscape (or whomever) could remove the UI and set the default value to 50 (or 500000, or 5) if they so wish.
why is this a netscape issue? having a reasonable default obviates the need for a user-level pref. keep it hidden for tweaking. no end user, mozilla or otherwise, would ever want to change this. if they really do, they can edit prefs.js. this is typical of why our prefs are a mess. mozilla is not a geek browser. once it becomes that, we're doomed.
I forget the discussions (which were in the newsgroup), but I think people had wildly different ideas of what was a 'good' value. Honestly I wouldn't care if the UI were to go away so long as the pref remained and the default was "reasonable" (say at least 50). I suspect the UI got created because it was easy and people wanted to play with it. However, I don't see this as a major minus to mozilla. Mozilla _is_ in many ways a geek browser; but one that's used as the base for a number of very much non-geek browsers (Netscape, etc). Someone making a mass-market browser from Mozilla will hide as least as many things as are added I'd think; probably more.
Component: History: Session → Document Navigation
QA Contact: claudius → docshell
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: