﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-tarius.wu-文章分类-OS</title><link>http://www.cnitblog.com/tarius.wu/category/112.html</link><description>Spend more time with your family and friends, eat your favorite foods, visit the places you love.</description><language>zh-cn</language><lastBuildDate>Tue, 27 Sep 2011 21:34:02 GMT</lastBuildDate><pubDate>Tue, 27 Sep 2011 21:34:02 GMT</pubDate><ttl>60</ttl><item><title>关于进程、线程和轻量级进程的一些笔记</title><link>http://www.cnitblog.com/tarius.wu/articles/2277.html</link><dc:creator>tarius.wu's Blog</dc:creator><author>tarius.wu's Blog</author><pubDate>Tue, 23 Aug 2005 10:58:00 GMT</pubDate><guid>http://www.cnitblog.com/tarius.wu/articles/2277.html</guid><wfw:comment>http://www.cnitblog.com/tarius.wu/comments/2277.html</wfw:comment><comments>http://www.cnitblog.com/tarius.wu/articles/2277.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tarius.wu/comments/commentRss/2277.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tarius.wu/services/trackbacks/2277.html</trackback:ping><description><![CDATA[

<p class="MsoNormal"><span style="font-family: 宋体;">在现代操作系统中，进程支持多线程。进程是资源管理的最小单元；而线程是程序执行的最小单元。一个进程的组成实体可以分为两大部分：线程集合资源集。进程中的线程是动态的对象；代表了进程指令的执行。资源，包括地址空间、打开的文件、用户信息等等，由进程内的线程共享。</span></p>


<p class="MsoNormal"><span style="font-family: 宋体;">线程有自己的私有数据：程序计数器，栈空间以及寄存器。</span></p>


<h3><span lang="EN-US">Why Thread?</span><span style="font-family: 宋体;">（传统单线程进程的缺点）</span></h3>


<p class="MsoNormal" style="margin-left: 18pt; text-indent: -18pt;"><!--[if !supportLists]--><span style="" lang="EN-US"><span style="">1．<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;
</span></span></span><!--[endif]--><span style="font-family: 宋体;">现实中有很多需要并发处理的任务，如数据库的服务器端、网络服务器、大容量计算等。</span></p>


<p class="MsoNormal" style="margin-left: 18pt; text-indent: -18pt;"><!--[if !supportLists]--><span style="" lang="EN-US"><span style="">2．<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;
</span></span></span><!--[endif]--><span style="font-family: 宋体;">传统的</span><span lang="EN-US">UNIX</span><span style="font-family: 宋体;">进程是单线程的，单线程意味着程序必须是顺序执行，不能并发；既在一个时刻只能运行在一个处理器上，因此不能充分利用多处理器框架的计算机。</span></p>


<p class="MsoNormal" style="margin-left: 18pt; text-indent: -18pt;"><!--[if !supportLists]--><span style="" lang="EN-US"><span style="">3．<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;
</span></span></span><!--[endif]--><span style="font-family: 宋体;">如果采用多进程的方法，则有如下问题：</span><span lang="EN-US"><br>
a. fork</span><span style="font-family: 宋体;">一个子进程的消耗是很大的，</span><span lang="EN-US">fork</span><span style="font-family: 宋体;">是一个昂贵的系统调用，即使使用现代的写时复制</span><span lang="EN-US">(copy-on-write)</span><span style="font-family: 宋体;">技术。</span><span lang="EN-US"><br>
b. </span><span style="font-family: 宋体;">各个进程拥有自己独立的地址空间，进程间的协作需要复杂的</span><span lang="EN-US">IPC</span><span style="font-family: 宋体;">技术，如消息传递和共享内存等。</span></p>


<h3><span style="font-family: 宋体;">多线程的优缺点</span></h3>


<p class="MsoNormal"><span style="font-family: 宋体;">多线程的优点和缺点实际上是对立统一的。</span></p>


<p class="MsoNormal"><span style="font-family: 宋体;">支持多线程的程序</span><span lang="EN-US">(</span><span style="font-family: 宋体;">进程</span><span lang="EN-US">)</span><span style="font-family: 宋体;">可以取得真正的并行</span><span lang="EN-US">(parallelism)</span><span style="font-family: 宋体;">，且由于共享进程的代码和全局数据，故线程间的通信是方便的。它的缺点也是由于线程共享进程的地址空间，因此可能会导致竞争，因此对某一块有多个线程要访问的数据需要一些同步技术。</span></p>


<h3><span style="font-family: 宋体;">三种线程——内核线程、轻量级进程、用户线程</span></h3>


<p class="MsoNormal" style="line-height: 150%;"><b style=""><span style="font-family: 宋体;">内核线程</span><span lang="EN-US"><o:p></o:p></span></b></p>


<p class="MsoNormal"><span style="font-family: 宋体;">内核线程就是内核的分身，一个分身可以处理一件特定事情。这在处理异步事件如异步</span><span lang="EN-US">IO</span><span style="font-family: 宋体;">时特别有用。内核线程的使用是廉价的，唯一使用的资源就是内核栈和上下文切换时保存寄存器的空间。支持多线程的内核叫做多线程内核</span><span lang="EN-US">(Multi-Threads kernel )</span><span style="font-family: 宋体;">。</span></p>


<p class="MsoNormal" style="line-height: 150%;"><b style=""><span style="font-family: 宋体;">轻量级进程</span><sup><span lang="EN-US">[*]</span></sup><span lang="EN-US"><o:p></o:p></span></b></p>


<p class="MsoNormal"><span style="font-family: 宋体;">轻量级线程</span><span lang="EN-US">(LWP)</span><span style="font-family: 宋体;">是一种由内核支持的用户线程。它是基于内核线程的高级抽象，因此只有先支持内核线程，才能有</span><span lang="EN-US">LWP</span><span style="font-family: 宋体;">。每一个进程有一个或多个</span><span lang="EN-US">LWPs</span><span style="font-family: 宋体;">，每个</span><span lang="EN-US">LWP</span><span style="font-family: 宋体;">由一个内核线程支持。这种模型实际上就是恐龙书上所提到的一对一线程模型。在这种实现的操作系统中，</span><span lang="EN-US">LWP</span><span style="font-family: 宋体;">就是用户线程。</span></p>


<p class="MsoNormal"><span style="font-family: 宋体;">由于每个</span><span lang="EN-US">LWP</span><span style="font-family: 宋体;">都与一个特定的内核线程关联，因此每个</span><span lang="EN-US">LWP</span><span style="font-family: 宋体;">都是一个独立的线程调度单元。即使有一个</span><span lang="EN-US">LWP</span><span style="font-family: 宋体;">在系统调用中阻塞，也不会影响整个进程的执行。</span></p>


<p class="MsoNormal"><span style="font-family: 宋体;">轻量级进程具有局限性。首先，大多数</span><span lang="EN-US">LWP</span><span style="font-family: 宋体;">的操作，如建立、析构以及同步，都需要进行系统调用。系统调用的代价相对较高：需要在</span><span lang="EN-US">user mode</span><span style="font-family: 宋体;">和</span><span lang="EN-US">kernel mode</span><span style="font-family: 宋体;">中切换。其次，每个</span><span lang="EN-US">LWP</span><span style="font-family: 宋体;">都需要有一个内核线程支持，因此</span><span lang="EN-US">LWP</span><span style="font-family: 宋体;">要消耗内核资源（内核线程的栈空间）。因此一个系统不能支持大量的</span><span lang="EN-US">LWP</span><span style="font-family: 宋体;">。</span></p>

<img src="http://www.cnitblog.com/images/cnitblog_com/tarius.wu/LWP.JPG" alt="LWP.JPG" border="0" height="312" width="458"><br>


<p class="MsoNormal"><span style="font-size: 9pt; font-family: 宋体;">注：</span><span style="font-size: 9pt;" lang="EN-US"><o:p></o:p></span></p>


<p class="MsoNormal" style="margin-left: 18pt; text-indent: -18pt;"><!--[if !supportLists]--><span style="font-size: 9pt;" lang="EN-US"><span style="">1．<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp; </span></span></span><!--[endif]--><span style="font-size: 9pt;" lang="EN-US">LWP</span><span style="font-size: 9pt; font-family: 宋体;">的术语是借自于</span><span style="font-size: 9pt;" lang="EN-US">SVR4/MP</span><span style="font-size: 9pt; font-family: 宋体;">和</span><span style="font-size: 9pt;" lang="EN-US">Solaris 2.x</span><span style="font-size: 9pt; font-family: 宋体;">。</span><span style="font-size: 9pt;" lang="EN-US"><o:p></o:p></span></p>


<p class="MsoNormal" style="margin-left: 18pt; text-indent: -18pt;"><!--[if !supportLists]--><span style="font-size: 9pt;" lang="EN-US"><span style="">2．<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp; </span></span></span><!--[endif]--><span style="font-size: 9pt; font-family: 宋体;">有些系统将</span><span style="font-size: 9pt;" lang="EN-US">LWP</span><span style="font-size: 9pt; font-family: 宋体;">称为虚拟处理器。</span><span style="font-size: 9pt;" lang="EN-US"><o:p></o:p></span></p>


<p class="MsoNormal" style="margin-left: 18pt; text-indent: -18pt;"><!--[if !supportLists]--><span style="font-size: 9pt;" lang="EN-US"><span style="">3．<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp; </span></span></span><!--[endif]--><span style="font-size: 9pt; font-family: 宋体;">将之称为轻量级进程的原因可能是：在内核线程的支持下，</span><span style="font-size: 9pt;" lang="EN-US">LWP</span><span style="font-size: 9pt; font-family: 宋体;">是独立的调度单元，就像普通的进程一样。所以</span><span style="font-size: 9pt;" lang="EN-US">LWP</span><span style="font-size: 9pt; font-family: 宋体;">的最大特点还是每个</span><span style="font-size: 9pt;" lang="EN-US">LWP</span><span style="font-size: 9pt; font-family: 宋体;">都有一个内核线程支持。</span><span style="font-size: 9pt;" lang="EN-US"><o:p></o:p></span></p>


<p class="MsoNormal"><span style="font-size: 9pt;" lang="EN-US"><o:p>&nbsp;</o:p></span></p>


<p class="MsoNormal" style="line-height: 150%;"><b style=""><span style="font-family: 宋体;">用户线程</span><span lang="EN-US"><o:p></o:p></span></b></p>


<p class="MsoNormal"><span lang="EN-US">LWP</span><span style="font-family: 宋体;">虽然本质上属于用户线程，但</span><span lang="EN-US">LWP</span><span style="font-family: 宋体;">线程库是建立在内核之上的，</span><span lang="EN-US">LWP</span><span style="font-family: 宋体;">的许多操作都要进行系统调用，因此效率不高。而这里的用户线程指的是完全建立在用户空间的线程库，用户线程的建立，同步，销毁，调度完全在用户空间完成，不需要内核的帮助。因此这种线程的操作是极其快速的且低消耗的。</span></p>

<img src="http://www.cnitblog.com/images/cnitblog_com/tarius.wu/Uthread1.JPG" alt="Uthread1.JPG" border="0" height="202" width="296"><br>


<p class="MsoNormal"><span style="font-family: 宋体;">上图是最初的一个用户线程模型，从中可以看出，进程中包含线程，用户线程在用户空间中实现，内核并没有直接对用户线程进程调度，内核的调度对象和传统进程一样，还是进程本身，内核并不知道用户线程的存在。用户线程之间的调度由在用户空间实现的线程库实现。</span></p>


<p class="MsoNormal"><span style="font-family: 宋体;">这种模型对应着恐龙书中提到的多对一线程模型，其缺点是一个用户线程如果阻塞在系统调用中，则整个进程都将会阻塞。</span></p>


<p class="MsoNormal" style="line-height: 150%;"><b style=""><span style="font-family: 宋体;">加强版的用户线程——用户线程</span><span lang="EN-US">+LWP<o:p></o:p></span></b></p>


<span style="font-size: 10.5pt; font-family: 宋体;">这种模型对应着恐龙书中多对多模型。用户线程库还是完全建立在用户空间中，因此用户线程的操作还是很廉价，因此可以建立任意多需要的用户线程。操作系统提供了</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">LWP</span><span style="font-size: 10.5pt; font-family: 宋体;">作为用户线程和内核线程之间的桥梁。</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">LWP</span><span style="font-size: 10.5pt; font-family: 宋体;">还是和前面提到的一样，具有内核线程支持，是内核的调度单元，并且用户线程的系统调用要通过</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">LWP</span><span style="font-size: 10.5pt; font-family: 宋体;">，因此进程中某个用户线程的阻塞不会影响整个进程的执行。用户线程库将建立的用户线程关联到</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">LWP</span><span style="font-size: 10.5pt; font-family: 宋体;">上，</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">LWP</span><span style="font-size: 10.5pt; font-family: 宋体;">与用户线程的数量不一定一致。当内核调度到某个</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">LWP</span><span style="font-size: 10.5pt; font-family: 宋体;">上时，此时与该</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">LWP</span><span style="font-size: 10.5pt; font-family: 宋体;">关联的用户线程就被执行。<br>
<img src="http://www.cnitblog.com/images/cnitblog_com/tarius.wu/Uthread2.JPG" alt="Uthread2.JPG" border="0" height="260" width="406"><br>
</span>

<h3><span style="font-family: 宋体;">小结：</span></h3>


<p class="MsoNormal"><span style="font-family: 宋体;">很多文献中都认为轻量级进程就是线程，实际上这种说法并不完全正确，从前面的分析中可以看到，只有在用户线程完全由轻量级进程构成时，才可以说轻量级进程就是线程。</span></p>

<br>
<img src ="http://www.cnitblog.com/tarius.wu/aggbug/2277.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tarius.wu/" target="_blank">tarius.wu's Blog</a> 2005-08-23 18:58 <a href="http://www.cnitblog.com/tarius.wu/articles/2277.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>文件系统</title><link>http://www.cnitblog.com/tarius.wu/articles/364.html</link><dc:creator>tarius.wu's Blog</dc:creator><author>tarius.wu's Blog</author><pubDate>Sun, 12 Jun 2005 14:20:00 GMT</pubDate><guid>http://www.cnitblog.com/tarius.wu/articles/364.html</guid><wfw:comment>http://www.cnitblog.com/tarius.wu/comments/364.html</wfw:comment><comments>http://www.cnitblog.com/tarius.wu/articles/364.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tarius.wu/comments/commentRss/364.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tarius.wu/services/trackbacks/364.html</trackback:ping><description><![CDATA[
<p class="MsoNormal"><span style="font-family: 宋体;">首先，文件系统应该被看作一种存储和定位数据的机制。为了提供对磁盘高效且便捷的访问，操作系统通过文件系统来实现存储、定位、和提取数据。文件系统有两个不同的设计问题。</span></p>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">第一个问题是如何定义文件系统对用户的接口。具体方面涉及到定义文件及其属性，文件所允许的操作，组织文件的目录结构。这一层就是普通用户对文件系统的第一映像，如文件的类型，读写权限，目录是树型结构还是其它结构。这一层通常被称为逻辑文件系统。</span></p>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">第二个问题是创建怎样的数据结构和算法来将逻辑文件系统映射到物理外存设备上。这一层可以称之为底层文件系统。</span></p>



<h2><span lang="EN-US">1 </span><span style="font-family: 黑体;">逻辑文件系统</span></h2>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">逻辑文件系统用来当作与用户的接口，用户不需要知道文件具体如何访问，只需知道文件名、文件在哪一个目录中，用户所具有的访问权限等。逻辑文件系统通过<b style="">文件控制块（</b></span><b style=""><span lang="EN-US">file control block</span></b><b style=""><span style="font-family: 宋体;">，</span><span lang="EN-US">FCB</span></b><b style=""><span style="font-family: 宋体;">）</span></b><span style="font-family: 宋体;">来维护文件结构，它包含文件的信息，如拥有者，权限和文件的位置。因此，</span><span lang="EN-US">FCB</span><span style="font-family: 宋体;">是逻辑文件系统和底层文件系统的联系纽带。在</span><span lang="EN-US">UNIX</span><span style="font-family: 宋体;">系统中，</span><span lang="EN-US">FCB</span><span style="font-family: 宋体;">被称做索引节点（</span><span lang="EN-US">i </span><span style="font-family: 宋体;">节点）；而在</span><span lang="EN-US">NTFS</span><span style="font-family: 宋体;">中将</span><span lang="EN-US">FCB</span><span style="font-family: 宋体;">的信息存在<b style="">主控文件表</b>中，主控文件表采用关系数据库结构，每个文件占一行。</span></p>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">除了</span><span lang="EN-US">FCB</span><span style="font-family: 宋体;">，在格式化后的磁盘中还应存在以下数据结构：</span></p>


<ul>
  <li><!--[if !supportLists]--><span style="font-family: Wingdings;" lang="EN-US"><span style="">&nbsp; </span></span><b style=""><span style="font-family: 宋体;">引导控制块（</span><span lang="EN-US">boot control block</span></b><b style=""><span style="font-family: 宋体;">）</span></b><span style="font-family: 宋体;">：存储从该分区引导操作系统所需要的信息。如内核镜像的位置，引导参数等。它通常为分区的第一块。如果该分区没有操作系统，那么这块的内容为空。</span><span lang="EN-US">UNIX</span><span style="font-family: 宋体;">文件系统称之为引导块，</span><span lang="EN-US">NTFS</span><span style="font-family: 宋体;">称之为分区引导扇区。</span></li>
  <li><!--[if !supportLists]--><span style="font-family: Wingdings;" lang="EN-US"><span style=""><span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp; </span></span></span><b style=""><span style="font-family: 宋体;">分区控制块（</span><span lang="EN-US">partition control block</span></b><b style=""><span style="font-family: 宋体;">）</span></b><span style="font-family: 宋体;">：包含分区的详细信息，如分区的块数，块的大小，空闲块的数量和指针。</span><span lang="EN-US">UNIX</span><span style="font-family: 宋体;">系统称之为超级块</span><span lang="EN-US">(super block)</span><span style="font-family: 宋体;">，</span><span lang="EN-US">NTFS</span><span style="font-family: 宋体;">称之为主控文件表（</span><span lang="EN-US">master file table</span><span style="font-family: 宋体;">）。</span></li>
  <li><!--[if !supportLists]--><span style="font-family: Wingdings;" lang="EN-US"><span style=""><span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp; 
</span></span></span><!--[endif]--><b style=""><span style="font-family: 宋体;">目录结构</span></b><span style="font-family: 宋体;">：用来组织文件。</span></li>
</ul>


<h3><span style="font-family: 宋体;">分区</span></h3>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">硬盘等非易失性存储设备在使用前必须先被格式化，格式化的含义就是规定这个硬盘中的某个分区的文件系统是什么格式，是</span><span lang="EN-US">ext2</span><span style="font-family: 宋体;">，</span><span lang="EN-US">ext3</span><span style="font-family: 宋体;">，还是</span><span lang="EN-US">windows</span><span style="font-family: 宋体;">的</span><span lang="EN-US">fat32</span><span style="font-family: 宋体;">，</span><span lang="EN-US">ntfs</span><span style="font-family: 宋体;">等，这种格式化信息写在硬盘分区的固定位置上，如磁盘标签或卷头上。这样，当操作系统或其他能读写硬盘的实体一旦访问到某一硬盘分区，就会先读该分区的文件系统格式，看看自己是不是支持这种文件系统格式，如果不支持，就会读不到数据，当然也无法往该分区写数据。典型的如</span><span lang="EN-US">DOS</span><span style="font-family: 宋体;">就不认识</span><span lang="EN-US">NTFS</span><span style="font-family: 宋体;">格式。分区是硬件级的划分，因此它们是独立于任何操作系统的。</span></p>


<h3><span style="font-family: 宋体;">文件和目录</span></h3>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">在</span><span lang="EN-US">UNIX</span><span style="font-family: 宋体;">中存在的任何东西都是文件，发生的任何事情都是进程。目录是文件类型的一种，目录中放置其所有组成文件的文件名和索引号（</span><span lang="EN-US">i</span><span style="font-family: 宋体;">节点），包括子目录在内。也就是说，目录是文件的分组集合。</span></p>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">目录实际上是一张表，每一项记录着所包含文件的文件名和一个指向该文件的指针。要访问一个文件，就必须先访问文件所在的目录，而这个目录可能是它上级目录的子目录。因此，访问文件的过程就是根据文件系统中最上层的目录来层层索引，先找到文件的起始地址，以找到文件的</span><span lang="EN-US">i</span><span style="font-family: 宋体;">节点，再从</span><span lang="EN-US">i</span><span style="font-family: 宋体;">节点上得到整个文件的物理存储信息和属性。</span></p>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">目录是一个表，查找表里的项目就带来了查找效率问题。一般目录列表有线性列表和哈希列表。其各自的效率问题这里不作讨论。</span></p>


<h2><span lang="EN-US">2 </span><span style="font-family: 黑体;">底层文件系统</span></h2>


<p class="MsoNormal"><span style="font-family: 宋体;">在底层文件系统里我们要关心磁盘空间的划分方式以及文件的存储方式。这里列出了三种最基本的方式，现实中的实现都是以它们为基础的变形。磁盘的划分方式也即所谓的分区格式。</span></p>


<h3><span style="font-family: 宋体;">磁盘空间连续分配</span></h3>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">连续分配要求每个文件在磁盘上占有一组连续的块。与内存空间的分配一样，连续分配的好处就是访问数据块的速度加快，比如在访问</span><span lang="EN-US">b</span><span style="font-family: 宋体;">块后访问</span><span lang="EN-US">b+1</span><span style="font-family: 宋体;">块时通常不需要移动磁头。只有从当前磁道的最后一个扇区到下个磁道的第一个扇区需要，需要移动一个磁道。连续分配的缺点和内存连续分配一样，就是带来了磁盘碎片。</span></p>


<h3><span style="font-family: 宋体;">链接分配</span></h3>


<p class="MsoNormal"><span style="font-family: 宋体;">硬盘的访问最小单元是块，一般是</span><span lang="EN-US">512B</span><span style="font-family: 宋体;">。采用链接分配，每个文件是磁盘块的链表；磁盘块分布在磁盘的任何地方。</span></p>


<p class="MsoNormal"><span style="font-family: 宋体;">文件目录包括文件第一块的指针和最后一块的指针。</span></p>




<p class="MsoNormal"><span style="font-family: 宋体;">例如有一个</span><span lang="EN-US">5</span><span style="font-family: 宋体;">块的文件从第</span><span lang="EN-US">9</span><span style="font-family: 宋体;">块开始，然后是</span><span lang="EN-US">16</span><span style="font-family: 宋体;">，</span><span lang="EN-US">1</span><span style="font-family: 宋体;">，</span><span lang="EN-US">10</span><span style="font-family: 宋体;">，</span><span lang="EN-US">25</span><span style="font-family: 宋体;">；每一块都有一个指向下一块的指针，</span><span lang="EN-US">-1</span><span style="font-family: 宋体;">表示最后一块。</span></p>


<p class="MsoNormal"><span style="font-family: 宋体;">链接分配的缺点有两个：一是它只能用于文件的顺序访问；要访问一个文件的第</span><span lang="EN-US">i</span><span style="font-family: 宋体;">块，就要从该文件的起始块开始。二是指针需要空间。一个块有</span><span lang="EN-US">512B</span><span style="font-family: 宋体;">，指针要占用</span><span lang="EN-US">4B</span><span style="font-family: 宋体;">。</span></p>


<p class="MsoNormal"><span style="font-family: 宋体;">一种优化的办法是将硬盘的最小访问单元定义成几个块的组合，叫做簇。比如一个簇</span><span lang="EN-US">4</span><span style="font-family: 宋体;">块。按簇而不是按块来分配。这种方法提高了访问速度和指针的占用比，但增加了磁盘碎片。</span></p>


<p class="MsoNormal"><span lang="EN-US">MS-DOS</span><span style="font-family: 宋体;">和</span><span lang="EN-US">OS/2</span><span style="font-family: 宋体;">使用的</span><span lang="EN-US">FAT(</span><span style="font-family: 宋体;">文件分配表</span><span lang="EN-US">)</span><span style="font-family: 宋体;">格式就是链接分配的一种变种。</span></p>


<h3><span style="font-family: 宋体;">索引分配</span></h3>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">索引分配可以解决链接分配不能有效地解决的随机访问问题，它把文件的所有块指针放在一起：索引块。</span></p>

<img src="http://www.cnitblog.com/images/cnitblog_com/tarius.wu/rr.JPG" alt="rr.JPG" border="0" height="336" width="440"><br>


<p class="MsoNormal"><span style="font-family: 宋体;">目录中文件条目包含索引块地址，索引块中的第</span><span lang="EN-US">i</span><span style="font-family: 宋体;">个条目指向文件的第</span><span lang="EN-US">i</span><span style="font-family: 宋体;">块。要读入第</span><span lang="EN-US">i</span><span style="font-family: 宋体;">块，只要读入索引块的第</span><span lang="EN-US">i</span><span style="font-family: 宋体;">项。</span></p>

<br>





<img src ="http://www.cnitblog.com/tarius.wu/aggbug/364.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tarius.wu/" target="_blank">tarius.wu's Blog</a> 2005-06-12 22:20 <a href="http://www.cnitblog.com/tarius.wu/articles/364.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内存管理单元 MMU</title><link>http://www.cnitblog.com/tarius.wu/articles/322.html</link><dc:creator>tarius.wu's Blog</dc:creator><author>tarius.wu's Blog</author><pubDate>Fri, 10 Jun 2005 08:30:00 GMT</pubDate><guid>http://www.cnitblog.com/tarius.wu/articles/322.html</guid><wfw:comment>http://www.cnitblog.com/tarius.wu/comments/322.html</wfw:comment><comments>http://www.cnitblog.com/tarius.wu/articles/322.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cnitblog.com/tarius.wu/comments/commentRss/322.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tarius.wu/services/trackbacks/322.html</trackback:ping><description><![CDATA[
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">现代操作系统及</span><span lang="EN-US">CPU</span><span style="font-family: 宋体;">硬件中，都会提供内存管理单元（</span><span lang="EN-US">memory management unit</span><span style="font-family: 宋体;">，</span><span lang="EN-US">MMU</span><span style="font-family: 宋体;">）来进行内存的有效管理。内存管理算法有许多，从简单的裸机方法到分页和分段策略。各种算法都有其优缺点，为特定系统选择内存管理算法依赖于很多因素，特别是系统的硬件设计。</span></p>


<h2><span lang="EN-US">1 </span><span style="font-family: 黑体;">内存管理的目的</span></h2>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">内存管理的目的是为了更好的使用内存（似乎是废话</span><span lang="EN-US">-,-</span><span style="font-family: 宋体;">）。
内存是现代操作系统运行的中心。操作系统中任何一个进程的运行都需要内存，但是，操作系统中的内存是有限的；另一方面，从安全的角度出发，进程都需要有自
己的内存空间，其他的进程都不能访问这个私有的空间；同时，内存的分配会导致内存碎片问题，严重影响计算机的性能。以上这三个问题就是一般内存管理算法所
需要处理的目标。</span></p>


<ul>
  <li><!--[if !supportLists]--><span style="font-family: Wingdings;" lang="EN-US"><span style=""><span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp; 
</span></span></span><!--[endif]--><span style="font-family: 宋体;">交换</span></li>
  <li><!--[if !supportLists]--><span style="font-family: Wingdings;" lang="EN-US"><span style=""><span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"></span></span></span><span style="font-family: 宋体;">内存保护</span></li>
  <li><!--[if !supportLists]--><span style="font-family: Wingdings;" lang="EN-US"><span style=""><span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp; 
</span></span></span><!--[endif]--><span style="font-family: 宋体;">碎片问题</span></li>
</ul>









<h2><span lang="EN-US">2 </span><span style="font-family: 黑体;">交换</span></h2>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">进程需要在内存中执行，但进程可以暂时从内存中<b style="">交换</b>（</span><span lang="EN-US">swap</span><span style="font-family: 宋体;">）出去到备份存储上，当需要时再调回到内存中去。</span></p>

<img src="http://www.cnitblog.com/images/cnitblog_com/tarius.wu/m1.JPG" alt="m1.JPG" border="0" height="386" width="545"><br>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">在基于优先级的交换调度算法中，如果一个更高优先级的进程来了且需要服务，内存管理可以交换出低优先级的进程，以便装入和执行更高优先级的进程。当高优先级的进程执行完毕之后，低优先级的进程可以交换回内存继续执行。这种交换有时被称之为滚出</span><span lang="EN-US">(roll out)</span><span style="font-family: 宋体;">、滚进</span><span lang="EN-US">(roll in)</span><span style="font-family: 宋体;">。</span></p>


<p class="MsoNormal"><span lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">通常一个交换出的进程需要交换回它原来的内存空间。这一限制是由地址捆绑方式决定的。如果捆绑是在汇编时或加载时决定的，那么就不可以移动到不同的位置。如果捆绑是在运行时决定，由于物理地址是在运行时才确定，那么进程可以移到不同的地址空间。</span></p>


<p class="MsoNormal"><b style=""><span style="font-family: 宋体;">交换的代价：交换时间</span><span lang="EN-US"><o:p></o:p></span></b></p>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">交换时间主要是指转移时间，总的转移时间和所交换的内存空间成正比。交换不需要或只需要很少的磁头移动，简单的说，交换空间通常作为磁盘的一整块，且独立于文件系统（如</span><span lang="EN-US">Linux</span><span style="font-family: 宋体;">的</span><span lang="EN-US">swap</span><span style="font-family: 宋体;">空间），因此使用就有可能很快。</span></p>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">交换需要花很多时间，而且进程执行时间却很少，故交换通常不执行，但只有在许多进程运行且内存吃紧时，交换才开始启动。</span></p>


<h2><span lang="EN-US">3 </span><span style="font-family: 黑体;">分页</span></h2>


<h3><span lang="EN-US">3.1</span><span style="font-family: 宋体;">内存保护和内存碎片的背景</span></h3>


<p class="MsoNormal" style="text-indent: 21pt;"><b style=""><span style="font-family: 宋体;">内存保护</span></b><span style="font-family: 宋体;">是指操作系统进程不受用户进程的影响，保护用户进程不受其他用户进程的影响。内存保护最基本的思路是进程使用逻辑地址空间，而内存管理单元所看的是物理地址。操作系统将逻辑地址分配给进程，</span><span lang="EN-US">MMU</span><span style="font-family: 宋体;">负责逻辑地址到物理地址的映射（转换，捆绑）。</span></p>


<p class="MsoNormal"><span lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">值得注意的是对于指令（程序）和数据映射到内存地址可以在以下步骤地任意一步执行：</span></p>


<ul>
  <li><!--[if !supportLists]--><span style="font-family: Wingdings;" lang="EN-US"><span style=""></span></span><span style="font-family: 宋体;">编译时：如果编译时就知道进程将在内存中的驻留地址，那么就可以生成<b style="">绝对代码</b>。如</span><span lang="EN-US">MS-DOS</span><span style="font-family: 宋体;">的</span><span lang="EN-US">COM</span><span style="font-family: 宋体;">格式程序。</span></li>
  <li><!--[if !supportLists]--><span style="font-family: Wingdings;" lang="EN-US"><span style=""></span></span><span style="font-family: 宋体;">加载时：如果编译时不知道程序将驻留在何处，那么编译器就必须要生成<b style="">可重定位代码</b></span><b style=""><span lang="EN-US">(relocatable code )</span></b><span style="font-family: 宋体;">。这种情况下，最后地址映射会延迟到加载时才确定，如果开始地址发生变换，必须重新加载程序，以引入新值。</span></li>
  <li><!--[if !supportLists]--><span style="font-family: Wingdings;" lang="EN-US"><span style=""><span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">
</span></span></span><!--[endif]--><span style="font-family: 宋体;">执行时：如果进程在执行时可以从一个内存段移到另一个内存段，那么映射必须延迟到执行时才进程。采用这种方法需要硬件的支持，目前绝大多数操作系统采用这种方法（基于分页、分段等）。</span></li>
</ul>









<p class="MsoNormal" style="text-indent: 21pt;"><b style=""><span style="font-family: 宋体;">内存碎片</span></b><span style="font-family: 宋体;">是操作系统内存分配的产物。最初操作系统的内存是连续分配的，即进程</span><span lang="EN-US">A</span><span style="font-family: 宋体;">需要某一大小的内存空间，如</span><span lang="EN-US">200KB</span><span style="font-family: 宋体;">，操作系统就需要找出一块至少</span><span lang="EN-US">200KB</span><span style="font-family: 宋体;">的连续内存空间给进程</span><span lang="EN-US">A</span><span style="font-family: 宋体;">。随着系统的运行，进程终止时它将释放内存，该内存可以被操作系统分配给输入队列里的其他等待内存资源的进程。</span></p>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">可以想象，随着进程内存的分配和释放，最初的一大块连续内存空间被分成许多小片段，即使总的可用空间足够，但不再连续，因此产生的内存碎片。</span></p>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">一
个办法是不再对内存空间进行连续分配。这样只要有物理内存就可以为进程进行分配。而实际上，不进行连续分配只是相对的，因为完全这样做的代价太大。现实
中，往往定出一个最小的内存单元，内存分配是这最小单元的组合，单元内的地址是连续的，但各个单元不一定连续。这样的内存小单元有页和段。</span></p>


<p class="MsoNormal"><span style="font-family: 宋体;">当然，分段和分页也会产生碎片，但理论上每个碎片的大小不超过内存单元的大小。</span></p>


<h3><span lang="EN-US">3.2 </span><span style="font-family: 宋体;">分页</span></h3>


<p class="MsoNormal"><span style="font-family: 宋体;">分页时一种内存管理方案，同时也提供了内存保护机制。它允许分配的物理内存地址可以是非连续的。</span></p>


<p class="MsoNormal"><span style="font-family: 宋体;">逻辑内存分为大小相等块的组合，这个块称之为页；物理内存则分为固定大小的帧</span><span lang="EN-US">(frame)</span><span style="font-family: 宋体;">。页大小应和帧大小相同，这是由硬件决定的。通常是</span><span lang="EN-US">2</span><span style="font-family: 宋体;">的幂，这样可以方便地将逻辑地址映射到物理地址。</span></p>


<b style=""><span style="font-size: 10.5pt; font-family: 宋体;">基于分页的逻辑地址到物理地址的映射<br>
<img src="http://www.cnitblog.com/images/cnitblog_com/tarius.wu/m2.JPG" alt="m2.JPG" border="0" height="436" width="527"><br>
</span></b>

<p class="MsoNormal"><span style="font-family: 宋体;">考虑</span><span lang="EN-US">32</span><span style="font-family: 宋体;">位地址。如果页大小是</span><span lang="EN-US">4KB</span><span style="font-family: 宋体;">，则需要</span><span lang="EN-US">12</span><span style="font-family: 宋体;">位来表示每一页中的某个具体地址，因此</span><span lang="EN-US">32</span><span style="font-family: 宋体;">位的逻辑地址中需要</span><span lang="EN-US">12</span><span style="font-family: 宋体;">位来对某一页中的具体地址寻址。这</span><span lang="EN-US">12</span><span style="font-family: 宋体;">位叫做页偏移。剩下的</span><span lang="EN-US">20</span><span style="font-family: 宋体;">位可以作为页码，可以有</span><st1:chmetcnv unitname="m" sourcevalue="1" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on"><span lang="EN-US">1M</span></st1:chmetcnv><span style="font-family: 宋体;">的页。逻辑地址可以表示为：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <img src="http://www.cnitblog.com/images/cnitblog_com/tarius.wu/m4.JPG" alt="m4.JPG" border="0" height="79" width="369"><br>
</span>

</p>
<p class="MsoNormal"><span style="font-family: 宋体;">寻址时，根据页码</span><span lang="EN-US">P</span><span style="font-family: 宋体;">查页表，找到该页对应的帧，将帧号与页偏移（也是帧偏移）组合即得到物理地址。这样也说明了为什么页大小要等于帧大小，因为页数要等于帧数。</span></p>


<p class="MsoNormal"><span style="font-family: 宋体;">例如，页大小为</span><span lang="EN-US">4K</span><span style="font-family: 宋体;">，页码</span><span lang="EN-US">11</span><span style="font-family: 宋体;">对应的帧码是</span><span lang="EN-US">10</span><span style="font-family: 宋体;">，即表示是第</span><span lang="EN-US">10</span><span style="font-family: 宋体;">块物理帧，也偏移为</span><span lang="EN-US">5</span><span style="font-family: 宋体;">，则逻辑地址</span><span lang="EN-US">0X0000b 005</span><span style="font-family: 宋体;">对应的物理地址是</span><span lang="EN-US">0X<st1:chmetcnv unitname="a" sourcevalue="0" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">0000a</st1:chmetcnv> 005</span><span style="font-family: 宋体;">。</span></p>


<h2><span lang="EN-US">3.3 </span><span style="font-family: 黑体;">分页的内存保护</span></h2>


<p class="MsoNormal"><span style="font-family: 宋体;">基于分页的操作系统在分配内存时分给进程所需要的页数，其对应物理内存的帧号同时装入该</span><span lang="EN-US">MMU</span><span style="font-family: 宋体;">的页表。同时页表上有一个标记为，指明该页是属于哪个进程的。甚至可以定义该页对于某个进程的读写权限。非法的读写操作会产生硬件陷阱（或内存保护冲突）。</span></p>


<h3><span lang="EN-US">3.4 </span><span style="font-family: 宋体;">分页的代价</span></h3>


<p class="MsoNormal"><span style="font-family: 宋体;">由上一节可知分页是基于查找表的，而在内存中存储这个</span><st1:chmetcnv unitname="m" sourcevalue="1" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on"><span lang="EN-US">1M</span></st1:chmetcnv><span style="font-family: 宋体;">个项目的页表本身就带来了内存消耗和查找速度问题。于是，页表通常需要硬件的支持，即将页表写在硬件</span><span lang="EN-US">MMU</span><span style="font-family: 宋体;">的寄存器中。</span></p>


<p class="MsoNormal"><span style="font-family: 宋体;">如果页表比较小，那么页表写在寄存器中可以加快查找速度。但绝大多数当代的计算机页表都非常大。对于这些页表，采用快速寄存器来实现页表就不太合理了。</span></p>


<span style="font-size: 10.5pt; font-family: 宋体;">一种办法是使用</span><b style=""><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">TLB</span></b><span style="font-size: 10.5pt; font-family: 宋体;">（</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">translation look-aside buffer</span><span style="font-size: 10.5pt; font-family: 宋体;">）。</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">TLB</span><span style="font-size: 10.5pt; font-family: 宋体;">是关联的寄存器，</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">TLB</span><span style="font-size: 10.5pt; font-family: 宋体;">条目由两部分组成：页号和帧号。<br>
<img src="http://www.cnitblog.com/images/cnitblog_com/tarius.wu/m5.JPG" alt="m5.JPG" border="0" height="440" width="555"><br>
</span>

<p class="MsoNormal" style="text-indent: 21pt;"><span lang="EN-US">TLB</span><span style="font-family: 宋体;">只包含页表中的一小部分条目，整个页表还是保存在内存中。当</span><span lang="EN-US">CPU</span><span style="font-family: 宋体;">产生逻辑地址后，其页号提交给</span><span lang="EN-US">TLB</span><span style="font-family: 宋体;">。如果找到了页号，那同时也就找到了帧号，就可以访问物理内存；如果页号不在</span><span lang="EN-US">TLB</span><span style="font-family: 宋体;">中（称为</span><span lang="EN-US">TLB</span><span style="font-family: 宋体;">失效），那就需要访问页表。在页表中找到帧号后，把页号和帧号增加到</span><span lang="EN-US">TLB</span><span style="font-family: 宋体;">中，这样下次再用时可以很快找到。如果</span><span lang="EN-US">TLB</span><span style="font-family: 宋体;">中条目已满，则操作系统会根据一个替换策略来替换条目。替换策略有很多，从最近最小使用替换到随机替换等。另外，有的</span><span lang="EN-US">TLB</span><span style="font-family: 宋体;">允许某些条目不被替换，如内核代码的条目。</span></p>


<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">有的</span><span lang="EN-US">TLB</span><span style="font-family: 宋体;">还在条目中保存地址空间保护标志符，用来唯一标志进程，以提供进程内存保护。</span></p>


<h3><span lang="EN-US">3.5 </span><span style="font-family: 宋体;">页表结构</span></h3>


<p class="MsoNormal"><span style="font-family: 宋体;">对于</span><span lang="EN-US">32</span><span style="font-family: 宋体;">位以及</span><span lang="EN-US">64</span><span style="font-family: 宋体;">位逻辑地址的计算机来说，其页表实在太过庞大。为了压缩页表，一个简单的方法是使用层次化分页算法，就是将页表再分页。（这实际上是一种索引的方法）</span></p>

<img src="http://www.cnitblog.com/images/cnitblog_com/tarius.wu/m6.JPG" alt="m6.JPG" border="0" height="79" width="392"><br>
<img src="http://www.cnitblog.com/images/cnitblog_com/tarius.wu/m7.JPG" alt="m7.JPG" border="0" height="258" width="554"><br>
<p class="MsoNormal"><span style="font-size: 10.5pt; font-family: 宋体;">即将</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">2^20</span><span style="font-size: 10.5pt; font-family: 宋体;">个页表项分为</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">2^10</span><span style="font-size: 10.5pt; font-family: 宋体;">个组，每个组里面有</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">2^10</span><span style="font-size: 10.5pt; font-family: 宋体;">项。这样只需要</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">2K*4=8K</span><span style="font-size: 10.5pt; font-family: 宋体;">的页表空间，且查找速度也有很大提升。例如原先最坏情况下要查</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">2^20</span><span style="font-size: 10.5pt; font-family: 宋体;">次，现在最坏只要</span><span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">2*2^10</span><span style="font-size: 10.5pt; font-family: 宋体;">次</span></p>

<img src ="http://www.cnitblog.com/tarius.wu/aggbug/322.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tarius.wu/" target="_blank">tarius.wu's Blog</a> 2005-06-10 16:30 <a href="http://www.cnitblog.com/tarius.wu/articles/322.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>