﻿<?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>C++博客-每天早晨叫醒你的不是闹钟,而是梦想-随笔分类-体系结构</title><link>http://www.cppblog.com/mmdengwo/category/16711.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 29 Apr 2011 16:14:37 GMT</lastBuildDate><pubDate>Fri, 29 Apr 2011 16:14:37 GMT</pubDate><ttl>60</ttl><item><title>认识编码（含有GBK,GB2312相关知识）</title><link>http://www.cppblog.com/mmdengwo/archive/2011/04/29/145308.html</link><dc:creator>沛沛</dc:creator><author>沛沛</author><pubDate>Fri, 29 Apr 2011 03:22:00 GMT</pubDate><guid>http://www.cppblog.com/mmdengwo/archive/2011/04/29/145308.html</guid><wfw:comment>http://www.cppblog.com/mmdengwo/comments/145308.html</wfw:comment><comments>http://www.cppblog.com/mmdengwo/archive/2011/04/29/145308.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mmdengwo/comments/commentRss/145308.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mmdengwo/services/trackbacks/145308.html</trackback:ping><description><![CDATA[<p>一、介绍字符编码、内码，顺带介绍汉字编码 <br>&nbsp;<br>字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早 <br>期的计算机使用7位的ASCII编码，为了处理汉字，程序员设计了用于简体中文的GB2312 <br>和用于繁体中文的big5。 <br>&nbsp;<br>GB2312(1980年)一共收录了7445个字符，包括6763个汉字和682个其它符号。汉字区的内 <br>码范围高字节从B0-F7，低字节从A1-FE，占用的码位是72*94=6768。其中有5个空位是 <br>D7FA-D7FE。 <br>&nbsp;<br>GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号，它分为汉字 <br>区和图形符号区。汉字区包括21003个字符。2000年的GB18030是取代GBK1.0的正式国家 <br>标准。该标准收录了27484个汉字，同时还收录了藏文、蒙文、维吾尔文等主要的少数民 <br>族文字。现在的PC平台必须支持GB18030，对嵌入式产品暂不作要求。所以手机、MP3一 <br>般只支持GB2312。 <br>&nbsp;<br>从ASCII、GB2312、GBK到GB18030，这些编码方法是向下兼容的，即同一个字符在这些方 <br>案中总是有相同的编码，后面的标准支持更多的字符。在这些编码中，英文和中文可以 <br>统一地处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼， <br>GB2312、GBK到GB18030都属于双字节字符集 (DBCS)。 <br>&nbsp;<br>有的中文Windows的缺省内码还是GBK，可以通过GB18030升级包升级到GB18030。不过 <br>GB18030相对GBK增加的字符，普通人是很难用到的，通常我们还是用GBK指代中文 <br>Windows内码。 <br>&nbsp;<br>这里还有一些细节： <br>&nbsp;<br>GB2312的原文还是区位码，从区位码到内码，需要在高字节和低字节上分别加上A0。 <br>&nbsp;<br>在DBCS中，GB内码的存储格式始终是big endian，即高位在前。 <br>&nbsp;<br>GB2312的两个字节的最高位都是1。但符合这个条件的码位只有128*128=16384个。所以 <br>GBK和GB18030的低字节最高位都可能不是1。不过这不影响DBCS字符流的解析：在读取 <br>DBCS字符流时，只要遇到高位为1的字节，就可以将下两个字节作为一个双字节编码，而 <br>不用管低字节的高位是什么。 <br>&nbsp; <br>&nbsp;<br>&nbsp;<br>二、关于编码 <br>&nbsp;<br>所谓编码，是以固定的顺序排列字符，并以此做为记录、存贮、传递、交换的统一内部 <br>特征，这个字符排列顺序被称为&#8220;编码&#8221;。和中文字库有关的常见编码有：大陆GB码、 <br>GBK码、港台BIG-5码等。下面简要介绍一下。 <br>&nbsp;<br>GB码 <br>&nbsp;<br>全称是GB2312-80《信息交换用汉字编码字符集 基本集》，1980年发布，是中文信息处 <br>理的国家标准，在大陆及海外使用简体中文的地区（如新加坡等）是强制使用的唯一中 <br>文编码。P-Windows3.2和苹果OS就是以GB2312为基本汉字编码， Windows 95/98则以GBK <br>为基本汉字编码、但兼容支持GB2312。 <br>&nbsp;<br>GB码共收录6763个简体汉字、682个符号，其中汉字部分：一级字3755，以拼音排序，二 <br>级字3008，以偏旁排序。该标准的制定和应用为规范、推动中文信息化进程起了很大作 <br>用。 <br>&nbsp;<br>1990年又制定了繁体字的编码标准GB12345-90《信息交换用汉字编码字符集 第一辅助 <br>集》，目的在于规范必须使用繁体字的各种场合，以及古籍整理等。该标准共收录6866 <br>个汉字（比GB2312多103个字，其它厂商的字库大多不包括这些字），纯繁体的字大概有 <br>2200余个。 <br>&nbsp;<br>Unicode编码(Universal Multiple Octet Coded Character Set) <br>&nbsp;<br>国际标准组织于1984年4月成立ISO/IEC JTC1/SC2/WG2工作组，针对各国文字、符号进行 <br>统一性编码。1991年美国跨国公司成立Unicode Consortium，并于1991年10月与WG2达成 <br>协议，采用同一编码字集。目前Unicode是采用16位编码体系，其字符集内容与ISO10646 <br>的BMP（Basic Multilingual Plane）相同。Unicode于1992年6月通过DIS（Draf <br>International Standard），目前版本V2.0于1996公布，内容包含符号6811个，汉字 <br>20902个，韩文拼音11172个，造字区6400个，保留20249个，共计65534个。 <br>&nbsp;<br>GBK编码(Chinese Internal Code Specification) <br>&nbsp;<br>GBK编码是中国大陆制订的、等同于UCS的新的中文编码扩展国家标准。GBK工作小组于 <br>1995年10月，同年12月完成GBK规范。该编码标准兼容GB2312，共收录汉字21003个、符 <br>号883个，并提供1894个造字码位，简、繁体字融于一库。 <br>&nbsp;<br>Windows95/98简体中文版的字库表层编码就采用的是GBK，通过GBK与UCS之间一一对应的 <br>码表与底层字库联系。 </p>
<p>&nbsp;<br>BIG5编码 <br>&nbsp;<br>是目前台湾、香港地区普遍使用的一种繁体汉字的编码标准，包括440个符号，一级汉字 <br>5401个、二级汉字7652个，共计13060个汉字。 <br>&nbsp;<br>方正748编码 <br>&nbsp;<br>所谓748编码，是指方正系统在长期应用过程中实施、制定的简、繁体字库编码方式，简 <br>体兼容GB2312且有所扩展，共7156字；繁体兼容GB12345并扩展全部BIG-5汉字，计14943 <br>字。此外，方正748编码还含有丰富的符号库。748编码仅用于方正软件和系统。<br>&nbsp; </p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/coffeemay/archive/2006/04/17/666213.aspx">http://blog.csdn.net/coffeemay/archive/2006/04/17/666213.aspx</a></p>
<img src ="http://www.cppblog.com/mmdengwo/aggbug/145308.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mmdengwo/" target="_blank">沛沛</a> 2011-04-29 11:22 <a href="http://www.cppblog.com/mmdengwo/archive/2011/04/29/145308.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>"PE文件格式"1.9版 完整译文（附注释）</title><link>http://www.cppblog.com/mmdengwo/archive/2011/04/29/145301.html</link><dc:creator>沛沛</dc:creator><author>沛沛</author><pubDate>Fri, 29 Apr 2011 03:03:00 GMT</pubDate><guid>http://www.cppblog.com/mmdengwo/archive/2011/04/29/145301.html</guid><wfw:comment>http://www.cppblog.com/mmdengwo/comments/145301.html</wfw:comment><comments>http://www.cppblog.com/mmdengwo/archive/2011/04/29/145301.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mmdengwo/comments/commentRss/145301.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mmdengwo/services/trackbacks/145301.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 标 题: 【翻译】&#8220;PE文件格式&#8221;1.9版 完整译文（附注释）作 者: ah007时 间: 2006-02-28,13:32链 接: http://bbs.pediy.com/showthread.php?threadid=21932$Id: pe.txt,v 1.9 1999/03/20 23:55:09 LUEVELSMEYER Exp $PE文件格式系列译文之...&nbsp;&nbsp;<a href='http://www.cppblog.com/mmdengwo/archive/2011/04/29/145301.html'>阅读全文</a><img src ="http://www.cppblog.com/mmdengwo/aggbug/145301.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mmdengwo/" target="_blank">沛沛</a> 2011-04-29 11:03 <a href="http://www.cppblog.com/mmdengwo/archive/2011/04/29/145301.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>操作系统 内存地址（逻辑地址、线性地址、物理地址）概念</title><link>http://www.cppblog.com/mmdengwo/archive/2011/04/25/144957.html</link><dc:creator>沛沛</dc:creator><author>沛沛</author><pubDate>Mon, 25 Apr 2011 06:03:00 GMT</pubDate><guid>http://www.cppblog.com/mmdengwo/archive/2011/04/25/144957.html</guid><wfw:comment>http://www.cppblog.com/mmdengwo/comments/144957.html</wfw:comment><comments>http://www.cppblog.com/mmdengwo/archive/2011/04/25/144957.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mmdengwo/comments/commentRss/144957.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mmdengwo/services/trackbacks/144957.html</trackback:ping><description><![CDATA[<p>逻辑地址（Logical Address） 是指由程序产生的与段相关的偏移地址部分。例如，你在进行C语言指针编程中，可以读取指针变量本身值(&amp;操作)，实际上这个值就是逻辑地址，它是相对于你当前进程数据段的地址，不和绝对物理地址相干。只有在Intel实模式下，逻辑地址才和物理地址相等（因为实模式没有分段或分页机制,Cpu不进行自动地址转换）；逻辑也就是在Intel 保护模式下程序执行代码段限长内的偏移地址（假定代码段、数据段如果完全一样）。应用程序员仅需与逻辑地址打交道，而分段和分页机制对您来说是完全透明的，仅由系统编程人员涉及。应用程序员虽然自己可以直接操作内存，那也只能在操作系统给你分配的内存段操作。</p>
<p>线性地址（Linear Address） 是逻辑地址到物理地址变换之间的中间层。程序代码会产生逻辑地址，或者说是段中的偏移地址，加上相应段的基地址就生成了一个线性地址。如果启用了分页机制，那么线性地址可以再经变换以产生一个物理地址。若没有启用分页机制，那么线性地址直接就是物理地址。Intel 80386的线性地址空间容量为4G（2的32次方即32根地址总线寻址）。</p>
<p>物理地址（Physical Address） 是指出现在CPU外部地址总线上的寻址物理内存的地址信号，是地址变换的最终结果地址。如果启用了分页机制，那么线性地址会使用页目录和页表中的项变换成物理地址。如果没有启用分页机制，那么线性地址就直接成为物理地址了。</p>
<p>虚拟内存（Virtual Memory） 是指计算机呈现出要比实际拥有的内存大得多的内存量。因此它允许程序员编制并运行比实际系统拥有的内存大得多的程序。这使得许多大型项目也能够在具有有限内存资源的系统上实现。一个很恰当的比喻是：你不需要很长的轨道就可以让一列火车从上海开到北京。你只需要足够长的铁轨（比如说3公里）就可以完成这个任务。采取的方法是把后面的铁轨立刻铺到火车的前面，只要你的操作足够快并能满足要求，列车就能象在一条完整的轨道上运行。这也就是虚拟内存管理需要完成的任务。在Linux 0.11内核中，给每个程序（进程）都划分了总容量为64MB的虚拟内存空间。因此程序的逻辑地址范围是0x0000000到0x4000000。</p>
<p>有时我们也把逻辑地址称为虚拟地址。因为与虚拟内存空间的概念类似，逻辑地址也是与实际物理内存容量无关的。 <br>逻辑地址与物理地址的&#8220;差距&#8221;是0xC0000000，是由于虚拟地址-&gt;线性地址-&gt;物理地址映射正好差这个值。这个值是由操作系统指定的。</p>
<p>&nbsp;</p>
<p>虚拟地址到物理地址的转化方法是与体系结构相关的。一般来说有分段、分页两种方式。以现在的x86 cpu为例，分段分页都是支持的。Memory Mangement Unit负责从虚拟地址到物理地址的转化。逻辑地址是段标识+段内偏移量的形式，MMU通过查询段表，可以把逻辑地址转化为线性地址。如果cpu没有开启分页功能，那么线性地址就是物理地址；如果cpu开启了分页功能，MMU还需要查询页表来将线性地址转化为物理地址：<br>逻辑地址 ----（段表）---&gt; 线性地址 — （页表）—&gt; 物理地址<br>不同的逻辑地址可以映射到同一个线性地址上；不同的线性地址也可以映射到同一个物理地址上；所以是多对一的关系。另外，同一个线性地址，在发生换页以后，也可能被重新装载到另外一个物理地址上。所以这种多对一的映射关系也会随时间发生变化。</p>
<p><br>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/leves1989/archive/2008/11/15/3305402.aspx"><u><font color=#0000ff>http://blog.csdn.net/leves1989/archive/2008/11/15/3305402.aspx</font></u></a></p>
<img src ="http://www.cppblog.com/mmdengwo/aggbug/144957.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mmdengwo/" target="_blank">沛沛</a> 2011-04-25 14:03 <a href="http://www.cppblog.com/mmdengwo/archive/2011/04/25/144957.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Cache：一个隐藏并保管数据的场所——组相联详解</title><link>http://www.cppblog.com/mmdengwo/archive/2011/04/25/144956.html</link><dc:creator>沛沛</dc:creator><author>沛沛</author><pubDate>Mon, 25 Apr 2011 06:01:00 GMT</pubDate><guid>http://www.cppblog.com/mmdengwo/archive/2011/04/25/144956.html</guid><wfw:comment>http://www.cppblog.com/mmdengwo/comments/144956.html</wfw:comment><comments>http://www.cppblog.com/mmdengwo/archive/2011/04/25/144956.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mmdengwo/comments/commentRss/144956.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mmdengwo/services/trackbacks/144956.html</trackback:ping><description><![CDATA[<p>原文标题：Cache: a place for concealment and safekeeping</p>
<p>原文地址：<a href="http://duartes.org/gustavo/blog/"><u><font color=#0000ff>http://duartes.org/gustavo/blog/</font></u></a></p>
<p>&nbsp;</p>
<p>[注：本人水平有限，只好挑一些国外高手的精彩文章翻译一下。一来自己复习，二来与大家分享。]</p>
<p>&nbsp;</p>
<p>本文简要的展示了现代Intel处理器的CPU cache是如何组织的。有关cache的讨论往往缺乏具体的实例，使得一些简单的概念变得扑朔迷离。也许是我可爱的小脑瓜有点迟钝吧，但不管怎样，至少下面讲述了故事的前一半，即Core 2的 L1 cache是如何被访问的：</p>
<p>&nbsp;<img height=461 alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/drshenlei/EntryImages/20090618/L1CacheExample.png" width=687 __1303711252890__="ev_4294414917"></p>
<p align=center>L1 cache &#8211; 32KB，8路组相联，64字节缓存线</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由索引拣选缓存组（行）</p>
<p>&nbsp;</p>
<p>在cache中的数据是以缓存线（line）为单位组织的，一条缓存线对应于内存中一个连续的字节块。这个cache使用了64字节的缓存线。这些线被保存在cache bank中，也叫路（way）。每一路都有一个专门的目录（directory）用来保存一些登记信息。你可以把每一路连同它的目录想象成电子表格中的一列，而表的一行构成了cache的一组（set）。列中的每一个单元（cell）都含有一条缓存线，由与之对应的目录单元跟踪管理。图中的cache有64 组、每组8路，因此有512个含有缓存线的单元，合计32KB的存储空间。</p>
<p>&nbsp;</p>
<p>在cache眼中，物理内存被分割成了许多4KB大小的物理内存页（page）。每一页都含有4KB / 64 bytes == 64条缓存线。在一个4KB的页中，第0到63字节是第一条缓存线，第64到127字节是第二条缓存线，以此类推。每一页都重复着这种划分，所以第0页第3条缓存线与第1页第3条缓存线是不同的。</p>
<p>&nbsp;</p>
<p>在全相联缓存（fully associative cache）中，内存中的任意一条缓存线都可以被存储到任意的缓存单元中。这种存储方式十分灵活，但也使得要访问它们时，检索缓存单元的工作变得复杂、昂贵。由于L1和L2 cache工作在很强的约束之下，包括功耗，芯片物理空间，存取速度等，所以在多数情况下，使用全相联缓存并不是一个很好的折中。</p>
<p>&nbsp;</p>
<p>取而代之的是图中的组相联缓存（set associative cache）。意思是，内存中一条给定的缓存线只能被保存在一个特定的组（或行）中。所以，任意物理内存页的第0条缓存线（页内第0到63字节）必须存储到第0组，第1条缓存线存储到第1组，以此类推。每一组有8个单元可用于存储它所关联的缓存线（译注：就是那些需要存储到这一组的缓存线），从而形成一个8路关联的组（8-way associative set）。当访问一个内存地址时，地址的第6到11位（译注：组索引）指出了在4KB内存页中缓存线的编号，从而决定了即将使用的缓存组。举例来说，物理地址0x800010a0的组索引是000010，所以此地址的内容一定是在第2组中缓存的。</p>
<p>&nbsp;</p>
<p>但是还有一个问题，就是要找出一组中哪个单元包含了想要的信息，如果有的话。这就到了缓存目录登场的时刻。每一个缓存线都被其对应的目录单元做了标记（tag）；这个标记就是一个简单的内存页编号，指出缓存线来自于哪一页。由于处理器可以寻址64GB的物理RAM，所以总共有64GB / 4KB == 224个内存页，需要24位来保存标记。前例中的物理地址0x800010a0对应的页号为524,289。下面是故事的后一半：</p>
<p>&nbsp;<img height=283 alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/drshenlei/EntryImages/20090618/selectingCacheLine.png" width=681 __1303711252890__="ev_5828963259"></p>
<p align=center><br>在组中搜索匹配标记</p>
<p>&nbsp;</p>
<p>由于我们只需要去查看某一组中的8路，所以查找匹配标记是非常迅速的；事实上，从电学角度讲，所有的标记是同时进行比对的，我用箭头来表示这一点。如果此时正好有一条具有匹配标签的有效缓存线，我们就获得一次缓存命中（cache hit）。否则，这个请求就会被转发的L2 cache，如果还没匹配上就再转发给主系统内存。通过应用各种调节尺寸和容量的技术，Intel给CPU配置了较大的L2 cache，但其基本的设计都是相同的。比如，你可以将原先的缓存增加8路而获得一个64KB的缓存；再将组数增加到4096，每路可以存储256KB。经过这两次修改，就得到了一个4MB的L2 cache。在此情况下，需要18位来保存标记，12位保存组索引；缓存所使用的物理内存页的大小与其一路的大小相等。（译注：有4096组，就需要lg(4096)==12位的组索引，缓存线依然是64字节，所以一路有4096*64B==256KB字节；在L2 cache眼中，内存被分割为许多256KB的块，所以需要lg(64GB/256KB)==18位来保存标记。）</p>
<p>&nbsp;</p>
<p>如果有一组已经被放满了，那么在另一条缓存线被存储进来之前，已有的某一条则必须被腾空（evict）。为了避免这种情况，对运算速度要求较高的程序就要尝试仔细组织它的数据，使得内存访问均匀的分布在已有的缓存线上。举例来说，假设程序中有一个数组，元素的大小是512字节，其中一些对象在内存中相距4KB。这些对象的各个字段都落在同一缓存线上，并竞争同一缓存组。如果程序频繁的访问一个给定的字段（比如，通过虚函数表vtable调用虚函数），那么这个组看起来就好像一直是被填满的，缓存开始变得毫无意义，因为缓存线一直在重复着腾空与重新载入的步骤。在我们的例子中，由于组数的限制，L1 cache仅能保存8个这类对象的虚函数表。这就是组相联策略的折中所付出的代价：即使在整体缓存的使用率并不高的情况下，由于组冲突，我们还是会遇到缓存缺失的情况。然而，鉴于计算机中各个存储层次的相对速度，不管怎么说，大部分的应用程序并不必为此而担心。</p>
<p>&nbsp;</p>
<p>一个内存访问经常由一个线性（或虚拟）地址发起，所以L1 cache需要依赖分页单元（paging unit）来求出物理内存页的地址，以便用于缓存标记。与此相反，组索引来自于线性地址的低位，所以不需要转换就可以使用了（在我们的例子中为第6到11位）。因此L1 cache是物理标记但虚拟索引的（physically tagged but virtually indexed），从而帮助CPU进行并行的查找操作。因为L1 cache的一路绝不会比MMU的一页还大，所以可以保证一个给定的物理地址位置总是关联到同一组，即使组索引是虚拟的。在另一方面L2 cache必须是物理标记和物理索引的，因为它的一路比MMU的一页要大。但是，当一个请求到达L2 cache时，物理地址已经被L1 cache准备（resolved）完毕了，所以L2 cache会工作得很好。</p>
<p>&nbsp;</p>
<p>最后，目录单元还存储了对应缓存线的状态（state）。在L1代码缓存中的一条缓存线要么是无效的（invalid）要么是共享的（shared，意思是有效的，真的J）。在L1数据缓存和L2缓存中，一条缓存线可以为4个MESI状态之一：被修改的（modified），独占的（exclusive），共享的（shared），无效的（invalid）。Intel缓存是包容式的（inclusive）：L1缓存的内容会被复制到L2缓存中。在下一篇讨论线程（threading），锁定（locking）等内容的文章中，这些缓存线状态将发挥作用。下一次，我们将看看前端总线以及内存访问到底是怎么工作的。这将成为一个内存研讨周。</p>
<p>&nbsp;</p>
<p>（在回复中Dave提到了直接映射缓存（direct-mapped cache）。它们基本上是一种特殊的组相联缓存，只是只有一路而已。在各种折中方案中，它与全相联缓存正好相反：访问非常快捷，但因组冲突而导致的缓存缺失也非常多。）</p>
<p>&nbsp;</p>
<p>[译者小结：</p>
<p>&nbsp;</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内存层次结构的意义在于利用引用的空间局部性和时间局部性原理，将经常被访问的数据放到快速的存储器中，而将不经常访问的数据留在较慢的存储器中。</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般情况下，除了寄存器和L1缓存可以操作指定字长的数据，下层的内存子系统就不会再使用这么小的单位了，而是直接移动数据块，比如以缓存线为单位访问数据。</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于组冲突，可以这么理解：与上文相似，假设一个缓存，由512条缓存线组成，每条线64字节，容量32KB。</p>
<p>a)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 假如它是直接映射缓存，由于它往往使用地址的低位直接映射缓存线编号，所以所有的32K倍数的地址（32K，64K，96K等）都会映射到同一条线上（即第0线）。假如程序的内存组织不当，交替的去访问布置在这些地址的数据，则会导致冲突。从外表看来就好像缓存只有1条线了，尽管其他缓存线一直是空闲着的。</p>
<p>b)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果是全相联缓存，那么每条缓存线都是独立的，可以对应于内存中的任意缓存线。只有当所有的512条缓存线都被占满后才会出现冲突。</p>
<p>c)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 组相联是前两者的折中，每一路中的缓存线采用直接映射方式，而在路与路之间，缓存控制器使用全相联映射算法，决定选择一组中的哪一条线。</p>
<p>d)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果是2路组相联缓存，那么这512条缓存线就被分为了2路，每路256条线，一路16KB。此时所有为16K整数倍的地址（16K，32K，48K等）都会映射到第0线，但由于2路是关联的，所以可以同时有2个这种地址的内容被缓存，不会发生冲突。当然了，如果要访问第三个这种地址，还是要先腾空已有的一条才行。所以极端情况下，从外表看来就好像缓存只有2条线了，尽管其他缓存线一直是空闲着的。</p>
<p>e)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果是8路组相联缓存（与文中示例相同），那么这512条缓存线就被分为了8路，每路64条线，一路4KB。所以如果数组中元素地址是4K对齐的，并且程序交替的访问这些元素，就会出现组冲突。从外表看来就好像缓存只有8条线了，尽管其他缓存线一直是空闲着的。</p>
<p>]</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/drshenlei/archive/2009/06/17/4277959.aspx"><u><font color=#0000ff>http://blog.csdn.net/drshenlei/archive/2009/06/17/4277959.aspx</font></u></a></p>
<img src ="http://www.cppblog.com/mmdengwo/aggbug/144956.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mmdengwo/" target="_blank">沛沛</a> 2011-04-25 14:01 <a href="http://www.cppblog.com/mmdengwo/archive/2011/04/25/144956.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>bus error和segment fault</title><link>http://www.cppblog.com/mmdengwo/archive/2011/04/25/144954.html</link><dc:creator>沛沛</dc:creator><author>沛沛</author><pubDate>Mon, 25 Apr 2011 06:00:00 GMT</pubDate><guid>http://www.cppblog.com/mmdengwo/archive/2011/04/25/144954.html</guid><wfw:comment>http://www.cppblog.com/mmdengwo/comments/144954.html</wfw:comment><comments>http://www.cppblog.com/mmdengwo/archive/2011/04/25/144954.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mmdengwo/comments/commentRss/144954.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mmdengwo/services/trackbacks/144954.html</trackback:ping><description><![CDATA[<p style="TEXT-INDENT: 2em">我们经常会发现有两种内存转储(core dump) &nbsp; <br>&nbsp; 一种是段故障（segment fault）通常是在一个非法的地址上进行取值赋值操作造成。 &nbsp; <br>&nbsp; 一种是总线错误（bus error）通常是指针强制转换，导致CPU读取数据违反了一定的总线规则。</p>
<p style="TEXT-INDENT: 2em">首先，core就是内存的意思，在半导体应用之前，内存是由铁氧化物圆环制造的（core），但一直沿用至今。</p>
<p style="TEXT-INDENT: 2em">而这两种错误，都是有硬件告知操作系统一个有问题的内存引用。操作系统通过信号，再将错误信息告知进程。缺省情况下，进程收到&#8220;总线错误&#8221;或&#8220;段错误&#8221;信号后，将信息转储并终止。当然也可以为这些信号设置一个信号处理程序（signal handler）。</p>
<p style="TEXT-INDENT: 2em">总线错误（bus error），几乎都是有内存未对齐读引起的。内存对齐，就是内存变量的地址只能是其大小的整数倍，这样存储的目的就是为了方便并快速存取内存。一般情况下，编译器都会做好内存对齐工作，为什么又会引发段故障呢？很多情况就是由指针和强制类型转换引起的，如：</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 24.1pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 7.5pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt"><font size=3>union{</font></span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 24.1pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 7.5pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt"><font size=3>&nbsp;&nbsp;&nbsp;&nbsp;char a[10];</font></span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 24.1pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 7.5pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt"><font size=3>&nbsp;&nbsp;&nbsp; int i;</font></span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 24.1pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 7.5pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt"><font size=3>}u;</font></span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 24.1pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 7.5pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt"><font size=3>int *p = (int *)&amp;(u.a[1]);</font></span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 24.1pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 7.5pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt"><font size=3>*p = 17;</font></span></p>
<p style="TEXT-INDENT: 2em">当然，还有一些其它原因会引起&#8220;总线错误&#8221;，如奇偶校验码错误，所引用的内存块不存在。但是现在，内存都有硬件电路检测和修正，一般不会再传到软件层了；除了驱动程序，一般也不会引用不存在的内存块。</p>
<p style="TEXT-INDENT: 2em">段错误，一般是由于引用不位于自己的地址空间的地址引起的。最常见的就是通过一个未初始化，或者有非法值的指针引起的，如：int *p = 0; *p = 7; 而导致指针的非法值可能是由于不同的编程错误引起的，比起&#8220;总线错误&#8221;更加间接。</p>
<p style="TEXT-INDENT: 2em">段错误一般是由硬件段表转换机构的错误引发，如Sun硬件中的内存管理单元(MMU)。</p>
<p style="TEXT-INDENT: 2em">还有一个微妙之处是，如果未初始化的指针恰好具有未对齐的值，它将产生总线错误，而不是段错误。</p>
<img src ="http://www.cppblog.com/mmdengwo/aggbug/144954.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mmdengwo/" target="_blank">沛沛</a> 2011-04-25 14:00 <a href="http://www.cppblog.com/mmdengwo/archive/2011/04/25/144954.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>