|
Mozilla中减少图像内存消耗的方案
当你运行Mozilla或者Firefox(火狐浏览器),并载入一个带有图片的网页的时候,它把解压成像素图(pixmaps)的图片保存在X服务器(X server)中。特别是,看起来它保持你打开的所有标签中的所有图片的像素图;即使标签是不可见的,图片仍然在你的X服务器的内存当中。
当你退出Firefox,X服务器可以聪明地把内存返回给内核。
当然,网页使用压缩的图片,以减少下载的时间。这些图片一旦解压,将占用大量的内存。
例如,我的一个目录中有大约4.3 MB的JPEG图片。
如果我解压这些图片,它们膨胀到大约67 MB的体积。
- $ mkdir uncompressed
- $ for i in jpegs/*.jpg; do convert $i uncompressed/`basename $i .jpg`.ppm; done
- $ du -s uncompressed
- 67172 uncompressed
复制代码
让我们来看看,当我们用Firefox(火狐)载入这些图片的时候会发生什么。我创建了一个简单的HTML页面,用<img>标签包含我的JPEG图片目录中的每一个文件,所以Firefox将载入所有的图片,解压它们,把解压后的数据转成适合X像素图片(X pixmaps)的格式,然后存入服务器。
为了得到内存消耗的大概数目,我使用ps和fabulous xrestop。Xrestop很像常用的top命令,但是它可以告诉你每一个(X)客户端使用了多少的X服务器(X server)资源。特别地,xrestop里有一栏告诉你一个客户端的像素图(pixmaps)使用了多少内存。
这里有一个ps and xrestop关于一个新启动的Firefox的输出。
- ps:
- USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
- federico 27833 20.7 4.6 55080 24136 pts/0 Sl 11:12 0:01 /opt/MozillaFirefox/lib/firefox-bin
- xrestop:
- res-base Wins GCs Fnts Pxms Misc Pxm mem Other Total PID Identifier
- 4400000 87 53 1 29 30 415K 4K 420K ? Mozilla Firefox
复制代码
所以我们得到的基数是客户端驻留了24MB内存,服务器上的像素图使用了415KB。记住,这是一个新启动的Firefox(火狐)的数据。
在载入我的那个充满JPEG图片的页面之后,我们得到:
- ps:
- USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
- federico 27833 4.7 5.0 56544 26172 pts/0 Sl 11:12 0:05 /opt/MozillaFirefox/lib/firefox-bin
- xrestop:
- res-base Wins GCs Fnts Pxms Misc Pxm mem Other Total PID Identifier
- 4400000 88 71 1 73 31 95327K 5K 95332K ? Mozilla Firefox
复制代码
哇!Firefox进程的本地内存空间(resident size)只增长了2MB,但是它却在服务器上创建了95MB的像素图。这里为什么比我们先前得到的解压缩图片后的67MB体积要大呢? 谁知道呢 -- 也许像素图需要更多的空间来对齐RGB数据的边界。
还记得我们压缩后的图片只占用4.3MB的空间吗?Firefox进程只增长了大约2MB:这表明它在把图片传给服务器之后并不自己保存压缩的图片。这很好:仅保存图像的一份拷贝。
然后,我在Firefox中打开了一个空标签,并且关闭了有图像的那个标签:
- ps:
- USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
- federico 27833 2.9 5.0 56544 26200 pts/0 Sl 11:12 0:06 /opt/MozillaFirefox/lib/firefox-bin
- xrestop:
- res-base Wins GCs Fnts Pxms Misc Pxm mem Other Total PID Identifier
- 4400000 91 83 1 46 32 24988K 5K 24994K ? Mozilla Firefox
复制代码
Firefox进程的本地内存只增长了一些,没有增大它的虚拟内存占用。所以,别担心这一点。不管怎么样,它把24.9MB的像素图留在服务器。那是为什么?那是浏览器的一部分缓存吗?或者是它泄漏的像素图?
让我们来找出答案。我再次载入那个带有JPEG图片的页面:
- ps:
- USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
- federico 27833 3.3 5.5 58568 28544 pts/0 Sl 11:12 0:09 /opt/MozillaFirefox/lib/firefox-bin
- xrestop:
- res-base Wins GCs Fnts Pxms Misc Pxm mem Other Total PID Identifier
- 4400000 105 89 1 78 38 95328K 6K 95334K ? Mozilla Firefox
复制代码
该进程的虚拟空间这一次只增长了大约2MB,而且它本地内存空间增长了大约2MB。注意到相比我们第一次载入那个带有JPEG图片的的页面的时候,稍微大了一点。 但是与我们在服务器中拥有的内存相比只是很不的一部分,所以现在我们不担心这一点。注意到服务器再次增长以便保持95MB的像素图。这与我们最初运行的情况一致, 所以我们可以有理由相信Firefox在X服务器中并没有泄漏像素图它只是把它们保存在那里作为浏览器的缓存。
到目前为止我们知道了什么?
o
是的,解压缩后的图像比压缩的大得多了。
o
Firefox无论在哪方面都没有保存多于一份的图像的拷贝。这一点是好的。
o
Firefox把所有标签中的图像以解压成像素图的格式保存在X服务器中。这并不算可怕,因为总得保存图像在某个地方。
但是,我们能够做得更好吗?也就是说,在我们需要把图像画到屏幕之前,我们能否只在(或者大部分只在)内存中保存压缩后的图像?
概念性的论证
让我们概述一下我们想要测试什么:
o
如果你必须保存图像在内存中,那么就保存为压缩格式(“像从网上下载的一样”)。如果这样做能节省什么内存呢?
o
当你需要把图像画到屏幕上时(例如用户滚动屏幕使用图片可见),即时地解压它。这样会导致糟糕的使用效果吗?
回答关于节省内存的问题,这们只需要比较图像压缩前后的体积。这很简单。
回答使用效果的问题,我们必须运行程序,滚动窗口,得到直观上的感觉。如果需要,我们可以使用工具或者配置文件让程序重负荷运行。
这个程序很简单:moz-images.cs。 下载它,然后看顶端的注释如何编译它。像这样运行它:
- mono moz-images.exe /directory/full/of/images mode
复制代码
选项模式可以是--server,--client或者--compressed。它们是这样的:
o
--server:预先载入所有的图像,为它们创建解压缩后的X像素图,释放压缩的数据。当需要重画时,它只需要复制适当的像素图到窗口里。
o
--client:预先载入所有的图像,把它们解压后保存在客户端作为GdkPixbuf对象。当需要重画时,它把适当的pixbuf区域发送到X服务器。
o
--compressed:这是非常有趣的一项。载入图像,但是以它们原先的压缩形式保存在内存中。当需要重画时,它解压将是可见的图像并送到X服务器。 当你滚动窗口使用图像不再可见时,程序释放图像解压后的数据;如果需要,它会压缩原先的数据。
我用ps和xrestop取得每一种情况的结果。为了确认所有的图像都保存在内存页面中,每一种情况我都上下滚动窗口一段时间,然后运行ps和xrestop。
- Mode Resident size Pixmaps in X server Total size Performance
- --server 15380 KB 92683 KB 108063 KB (1)
- --client 85324 KB 384 KB 85708 KB (2)
- --compressed 19204 KB 384 KB 19588 KB (3)
复制代码
- 对于 --server, 程序花了很长时间来启动,我的机器开始交换内存,为过度增长的X服务器进程创建空间。第二次启动就快多了,因为内存中已经分配了空间了。 预先解压所有的图像时也花了一些时间(在1到2秒之间)。滚屏超级快,像预测的一样,因为所有的像素图已经存在于内存和服务器中了。 注意到在客户端我们使用了相对较少的内存,在服务器端却使用了大量的内存。累积的内存一共是108063 KB。
- 对于 --client, 程序在一个可以接受的相对快的时间内启动,支使内存中已经分配好了空间。预先解压所有的图像时也花了一些时间。 滚屏超级快,我没有发现与--server选项时有什么区别。看起来程序好像在这台机器上作为服务器运行。 确实,我们在服务器端只使用了很少的内存,但是在客户端,累积的内存一共是85708 KB。
- 对于 --compressed, 程序启动比其它选项快得多了,因为它不需要预先解压所有的图像。如果你猛地快速拉动滚动条向上或者向下时,滚动有点卡。 在你使用滚轮或者使用滚动条上的箭头以平时阅读网页的速度滚屏时,停滞现象特别明显。注意到在客户端我们使用了相对较少的内存,而且在服务器端内存占用特别少。 累积的内存一共是19588 KB
而且,比较使用--compressed和--server时的本地内存空间(resident size)占用情况。前者,我们花了19204 KB;后者,我们花了15380 KB。 差异只有4MB。这与最初我们测量压缩的JPEG图片的体积匹配。
总结
对于Firefox,保存压缩后的,下载来的图像在客户端可以很大程度上减少内存消耗。我的程序就是一个概念性的证明, 并且在减少即时解压图像造成停滞现象方面并没有做任何称道的东西。Firefox可以做得非常好;在你阅读可视区域内存的时候, 也许它可以预先解压邻近可视区域的图像。我和硬盘的提前读取一样。
使用那个用来作概念性证明的程序,我们把累积的内存从108063 KB减少到了19588 KB -- 也就是说,5.5的因子。
=====================================================
英文原文在:http://primates.ximian.com/~federico/news-2005-11.html
HTML格式的中文译文在:http://www.ideawu.net/linux/firefox_mem.html
如果你发现有翻译错误,请与我联系。
原文是http://primates.ximian.com/~federico/news-2005-11.html 的一部分。如果你发现作者的分析有问题,请与原作者联系。 |
|