Showing posts with label firefox. Show all posts
Showing posts with label firefox. Show all posts

Tuesday, August 16, 2011

Browser tab overload

After a couple of years of using the excellent Opera browser, I switched to Firefox after some crashes and extremely high memory usage. It turns out that Opera was doing pretty well given that I had some 200 tabs open, though... (yes, I find interesting articles quicker than I read them, and if mail myself the links or put them in a "to read" folder, well, they seem to not get read either).

Anyway, with addons and things, I've grown accustomed to Firefox now, and a recent-ish update which forces JS events from background events/timers to be processed at most once per second really helped with CPU usage.
However, it still struggles a bit with some 100 tabs open on this laptop, and actually crashes with an out-of-memory exception on my 32-bit Vista box from time to time. Not that it explains this or anything, it just vanishes and pops up a crash reporter which doesn't seem to explain the crash; I had to run Firefox under WinDbg to get a proper, source-line annotated stack trace.

One workaround for this is to just not be so lazy and to read articles immediately and follow links in a depth-first way, rather than the exponentially disastrous strategy of reading a Wikipedia article and clicking open 12 interesting links into background tabs, then doing the same for each of those tabs if I ever get that far.

Until I have the discipline to do that, though (i.e. never), I found a couple of Javascript bookmarklets are helpful.
So I stole a few bookmarklets to zap plugins, events and timers from here and taped them together into one "Zap all" snippet. Going through the roughly five million open and unread Lifehacker tabs and zapping off the Javascript machinery and other cruft managed to reduce the CPU usage to a respectable ~1% mostly. And pared the RAM usage from 1.5 gigs down to just under 1 gig on that Vista box.

Screw solving the underlying problem when you have bookmarklets!

Obsolescence update: A recent feature in Firefox (at least the Aurora 8.0x releases) allows you to set tabs to load lazily (i.e. a tab won't automatically load after opening Firefox, until you activate that tab)... this is perfect for messy users like myself who end up with more tabs than they can eat - it seems to work really well.

Friday, June 17, 2011

Closed windows from a crashed Firefox: Dig [out of] your own grave and save!

Well, I don't know what happened. The Windows box went down for a reboot due to the usual bundle of patches for Windows bugs. Somewhere along the line, Firefox managed to close the window with all my (way too many) tabs, and when I rebooted, it opened up on the Mozilla homepage. Burn.

No problem, going to about:sessionrestore displays a list of... empty. Oh.

Ok then. A quick look in the profile dir (%APPDATA%\Mozilla\Firefox\Profiles\*.default) shows that the sessionstore.js and backup are over 4 megs in size - that looks promising. So I copy them and quit Firefox.
Inside sessionstore.js is a gigantic JSON string. Inside that, I find a closed tab (the session restore tab which I had given up on), with apparently another full JSON string in the #sessionData field. After decoding that, I find an empty list of windows, and a list of _closedWindows including my main window with many many tabs. Yay, I can just swap them then.

Here's a little program in Lua which might help resurrect your tabs/windows if something similar happens to you. It uses the very fast dkjson library (the whole read/decode/futz/encode/write process for a 4.5mb file takes about 1.25 seconds on my run-of-the-mill desktop using LuaJIT).

In this case, there was an open window with one closed tab containing an about:sessionrestore form...
  json = require('dkjson')

  print('Reading file...')
  local session = assert(io.open('sessionstore.js', 'r'))
  local session_data = session:read('*all')
  print('Parsing ('..#session_data..' bytes)...')
  local obj, pos, err = json.decode(session_data, 1, json.null)
  if err then error(err) end
  print('Success! table size: '..#obj, pos, err)

  -- I closed the session restore tab since the list was empty.
  -- Turns out it still had the closed window data, so
  -- we can extract that. You may have to change this.
  local data = obj.windows[1]._closedTabs[1].state.
      entries[1].formdata['#sessionData']

  -- parse it, swap open/closed windows
  local data_p = json.decode(data, 1, json.null)
  print('Decoded, swapping closed and open windows')
  local old_windows = data_p.windows
  data_p.windows = data_p._closedWindows
  data_p._closedWindows = old_windows

  print('Encoding')
  local outf = assert(io.open('sessionstore-rec-fixed.js', 'w'))
  outf:write(json.encode(data_p))
  outf:close()

In this case, the open windows had suddenly become closed windows... (this just happened now, the hell Aurora?)
  json = require('dkjson')
  print('Reading file...')
  local session = assert(io.open('sessionstore.js', 'r'))
  local session_data = session:read('*all')
  print('Parsing ('..#session_data..' bytes)...')
  local obj, pos, err = json.decode(session_data, 1, json.null)
  if err then error(err) end

  print('Success! table size: '..#obj, pos, err)
  print('Decoded, swapping closed and open windows')
  local old_windows = obj.windows
  obj.windows = obj._closedWindows
  obj._closedWindows = old_windows

  print('Encoding')
  local outf = assert(io.open('sessionstore-rec-fixed.js', 'w'))
  outf:write(json.encode(obj))
  outf:close()