关于计算机原理:twos-complement-2的补码
计算机原理中,是只有加法运算逻辑的,X-Y 减法换算成,X + Y的2的补码相当如-Y 实际上等于2的补码, 即Y取反加一https://www.ruanyifeng.com/blog/2009/08/twos_complement.html
计算机原理中,是只有加法运算逻辑的,X-Y 减法换算成,X + Y的2的补码相当如-Y 实际上等于2的补码, 即Y取反加一https://www.ruanyifeng.com/blog/2009/08/twos_complement.html
联合CMU CSAPP课程和本人看的教材做的笔记。 数据类型大小C的不同类型数据结构的大小。记住几个罕用的,char是1个byte,short是2个,int是4个。 C里的位运算和逻辑运算不要搞混。比方&和&&,&是按位与,&&是且运算,位运算的后果仍是一个不同的数值,逻辑运算的后果不是0就是1。 左移和右移位左移会把高位的移除,低位的补零。 右移有逻辑右移和算术右移。 逻辑右移和左移相似,低位移除,高位补0。算术右移低位移除,高位补的是符号位。 补码(符号数示意)正数示意的思路是,最高位作为符号位,因为当最高位取为1的时候,正好能够把这串比特示意的数字范畴拆成两半。比方我打算用4个比特示意数字,能够示意16个,1000的十进制是8,那么在1000以下的和1000以上的各能示意8个数字,就能够别离示意负数和正数了。 如下,16位示意的无符号数和有符号数的范畴。最大的正数是最高位1其余0,最大的负数是最高位0其余1,所以在负数的最大值再加个1,溢出的数值就是最大的正数。 上面的公式示意了二进制位的无符号和有符号数的公式。公式就是二进制转十进制的加权求和,留神有符号数,符号位以下的位的权重和无符号数是一样的,只有符号位的权重不一样,带了负号。 C语言的<limits.h>里的宏ULONG_MAX,LONG_MAX,LONG_MIN能够取得本机器上符号数的范畴。 常量无非凡申明的状况下默认是按有符号示意,如果前面加上U则是无符号,如0U,1234U。 类型转换C语言中,显式类型转换就是用显式地写进去的转换操作,比方用了函数,或者(int)a这种模式。隐式类型转换就是没有显式地写进去,但为了执行命令零碎主动做的转换,常产生在赋值和逻辑比拟中。 比方int a和unsigned int b,令a=b就产生了隐式类型转换,b会被转换成有符号类型,再赋给a,或者执行a<b,也会产生隐式转换。 有符号类型和无符号类型混用,无非凡申明的状况下,总是有符号会被转换成无符号。例如,如果-1和0U做比拟,后果是-1大于0U,因为-1的位级示意是全1,对应的无符号数就最大的负数。所以,当无符号数和有符号数混用时,都是负数没有关系,要小心有符号数是正数的状况。 老师补充了编程中典型的例子。上面是个死循环,因为i是无符号的,所以永远会是负数。位级的解释就是i最初减小到0U,再减去1后的-1是全1,对应的无符号数就是最大负数。 unsigned i;for(i=n-1;i>=0;i--){ func(a[i]); //do anything}再来个坑。如果刚开始把i申明成有符号了,然而循环条件这么写: int i;for(i=n-1;i-sizeof(char)>=0;i--){ func(a[i]); //do anything}结果也是死循环。因为sizeof返回的是无符号数,i和它做运算的后果始终还是无符号数。所以要分外留神隐式转换。 拓展和截断从k位的数字拓展到k+N位的数字,放弃数值大小不变,只有对符号位拓展就行了。能够本人用之前的加权求和公式计算一下,实际上拓展出的N位符号位,和只有1位的后果正好是一样的。 因而,C对短类型转长类型,比方short转int,做的事件就在后面拓展符号位(精确地说有符号数才有符号位,意思晓得了就行)。 而从长位到短位的数据转换,如uint转ushort,会把高位的数据间接截断,在数值上的后果就是做了一次对高位代表的权重的取余。 举个例子,思考无符号数,11011是16+8+0+2+1=27,截掉最高位1,失去1011,1011=8+0+2+1=11,11就是27mod16。 而对于有符号数,截断的过程中正数可能会变正,负数可能会负,要分外留神,如int转short。 整数加减法,溢出计算两个无符号数相加,像十进制那样做进位加法就能够,然而可能会存在最高位有进位的状况,也就是说,两个N位的数字相加,最终后果有时须要N+1位保留,然而容量只有N位,机器的做法是舍去多进去的一位,只保留N位,这就引出了溢出问题。 假如有4个bit示意无符号整数,能示意的范畴是0到15,如果计算8+12,实践上后果是20,但理论后果是4,产生了溢出,溢出的法则是:实践后果mod/舍去位的权重,即4=20mod16。 对于有符号整数的情景,如果也用4个bit示意,能示意的范畴是-8到+7,如果计算7+1,实践后果是8,理论后果是0111+0001=1000,这是最大的正数,即-8,产生了正溢出。如果计算(-8)+(-1),实践后果是-9,理论后果是1000+1111=0111,这是最大的负数,即7,产生了负溢出。不难发现溢出的法则是,从相同的最大值方向再从新轮次,刚好产生正溢出时会变成最大的正数,反之一样。 乘除的后果是相似的,产生溢出后的理论后果也是相当于做了模操作。 总结一下,产生溢出时做的操作就是高位截断,所以如果计算溢出后的理论后果的值,只有先计算出它的实践后果(二进制示意),而后依据它的数据类型的容量位数去截断高位,保留下来的就是理论后果。 幂数据左移k位就相当于乘以2的k次幂,这是编程中常见的操作。如0011=3,左移1位就是0110,正好是6,再左移一位就是1100=12。解决2的k次幂乘积运算时,编译器就会将其优化为左移运算。 如果是做2的k次幂的除法,也只有右移即可,如果无奈整除,会向下取整。留神对于有符号数,是算术右移,然而本人计算一下理论后果不是向下取整,是向上取整了,所以零碎的做法是先对被除数加一个偏移量1,而后再做除法,这样最终的后果也是向下取整模式的,放弃了对立。 相反数想得到一个有符号数x的相反数-x,只有对其取反再+1。其实就是补码的一种疾速计算方法。 小端&大端指的是字节存储程序,有小端模式和大端模式,目前绝大多数机器应用小端模式,如x86的机器,ARM处理器。 假如有个4字节数0x01234567,直观上看,咱们认为这个数字是从左到右的,也就是说右边是数据的低位,左边是数据的高位,存储时内存地址从低到高也对应数据的从左到右。大端序就是这么存储,然而小端序反了过去,左边的数字会被存储到地址的低位,即67存在最低位,01存在最高位。 浮点数浮点数的示意办法借鉴了迷信计数法的思维,迷信计数法是如下的模式: 只须要正负号,小数和指数三个局部就能够示意一个十进制数。同理,二进制数也能够示意成: S决定正负号,称为符号位,F决定小数局部,称为“尾数”,E决定指数局部,称为“阶码”,或者指数。 如果用32位的二进制串示意,能够调配如下的格局: 单精度浮点数,阶码有8位。 十进制浮点数转二进制示意的公式,尾数不难理解,要害是了解指数局部的“偏移量”的概念。 其实想对指数局部编码,当然能够沿用补码的模式,假如指数是-1,就用1111 1111示意,-128就用1000 0000示意,+1就用0000 0001示意,+127就用0111 1111示意。只不过这样干的话,比拟两个浮点数的大小时不够直观,对于两个规格化的浮点数,符号雷同时,指数大的那个会大一个量级以上,单从数值上看,1000 0000是比0000 0001要大的,但转补码后,实际上前者比后者小。另一方面,纯0,无穷大等,十分十分靠近0的小数等非凡的数字,怎么示意进去? 于是IEEE想的方法就是扭转一下映射关系。咱们心愿用一种新的编码方式示意指数局部,叫“阶码”,使得对于指数,原来是正的a>b,转二进制后仍是a>b,负的c>d,转二进制后仍是c>d,且a>b>c>d,说白了,像无符号整数那样不扭转递增关系。因而,阶码是不像补码那样有个符号位的,它是这么示意的: 1000 0000用来示意+1,向上递增就是正整数,以下的局部就是负整数。这样正好把示意范畴拆成两半。察看这个二进制示意,和+1本来的补码0000 0001相差多少?相差127(0111 1111),即0000 0001 + 0111 1111 = 1000 0000。就是说—— ...
计算机体系-常识树
download:计算机根底更适宜程序员的编程必备基础知识2022新版Android完满解决了输入框被遮挡的问题。序前段时间呈现了webview的输入框被软键盘挡住的问题。通过解决,顺便做了一些输入框栏目的汇总。在失常状况下,输入框被阻塞个别状况下,输入框被输入法屏蔽。个别能够通过设置softInputMode为window来解决。window.getAttributes()。softInputMode = WindowManager。LayoutParams.XXX有三种状况:(1)SOFT_INPUT_ADJUST_RESIZE:布局将由软键盘置顶。(2)SOFT_INPUT_ADJUST_PAN:只向上推输入框(即只向上推一部分间隔)(3)SOFT_INPUT_ADJUST_NOTHING:什么都不做(就是什么都不做)SOFT_INPUT_ADJUST_PAN和SOFT_INPUT_ADJUST_RESIZE的区别在于,SOFT_INPUT_ADJUST_PAN只是把输入框放在下面,而SOFT_INPUT_ADJUST_RESIZE会把整个布局放在下面,会有一种输入框显示和暗藏时布局高度动态变化的视觉效果。如果你的输入框梗塞,个别能够通过设置SOFT_INPUT_ADJUST_PAN来解决。如果你的输入框没有被屏蔽,然而软键盘弹出来了,布局就会被推上去。如果不想上推,能够设置SOFT_INPUT_ADJUST_NOTHING。SoftInputMode是window的属性。你在Mainifest中为Activity设置,也为window设置。如果是Dialog或者popupwindow,能够通过getWindow()间接设置。失常状况下,设置该属性能够解决问题。Webview的输入框被阻止然而,如果Webview的输入框被阻止,则设置该属性可能有效。在Webview的状况下,SOFT_INPUT_ADJUST_PAN将不起作用。而后,如果是Webview,并且你依然关上沉迷模式,则SOFT_INPUT_ADJUST_RESIZE和SOFT_INPUT_ADJUST_PAN都将不起作用。我去查资料,发现这是经典的5497期。许多在线解决方案都是通过androidbug 5497解决办法。这个解决办法很好找,我就不贴了。原理是监控视图树的变动,而后计算高度,再动静设置。这个计划的确能够解决问题,然而我感觉这个操作有很多不可控因素。说白了,某些模型或者状况下会有其余bug,会导致你写一些判断逻辑来应答非凡状况。解决办法是不必沉迷模式,而后用SOFT_INPUT_ADJUST_RESIZE就能够解决。然而有时候这个窗口显示的时候须要沉迷模式,特地是一些适宜刘海温和水滴屏的场景。setSystemUiVisibility(视图。SYSTEM UI FLAG _ LAYOUT _全屏)复制代码我的第一反馈是扭转布局。窗户。setLayout(ViewGroup。LayoutParams.MATCH_PARENT,ViewGroup。layout params . WRAP _ CONTENT);复制代码这样能够失常向上推子弹框,然而控件外部也应用了WRAP_CONTENT,导致SOFT_INPUT_ADJUST_RESIZE扭转了布局,而后就不能复原原样了,也就是会变形。而SOFT_INPUT_ADJUST_RESIZE如果WRAP_CONTENT不应用固定高度也是有效的。没关系,还有方法。在MATCH_PARENT的状况下,咱们把fitSystemWindows设置为true,然而这个属性会在顶部让出一个平安间隔,成果就是向下偏移状态栏的高度。在这种状况下,能够设置边距来解决顶部偏移的问题。params . top margin = status height = = 0?-120:-status height;view . setlayoutparams(params);复制代码此操作能够解决顶部偏移的问题,但布局可能会被垂直压缩。这个我还没有齐全测试过。我感觉你的布局高度固定的话,可能不会受影响。然而我的webview是自适应的,webview里的内容也是自适应的,所以我呈现了版面垂直压缩的状况。例如,视图的高度是800,状态栏的高度是100。设置fitSystemWindows后,成果是视图显示700,paddingTop 100。对于这种成果,设置params.topMargin =-100,而后视图显示700和paddingTop 100。它能够在视觉上打消顶部偏移,但没有解决布局的垂直压缩问题。所以最终的解决方案是扭转WindowInsets的Rect(我稍后会解释这意味着什么)具体操作是将以下两种办法增加到您的自定义视图中@笼罩public void setFitsSystemWindows(boolean fitSystemWindows){fitSystemWindows = truesuper . setfitssystemwindows(fitSystemWindows);} @笼罩受爱护的布尔fitSystemWindows(矩形插入){Log.v("mmp ","测试顶部偏移量:"+inserts . top);insets . top = 0;返回super . fitsystemwindows(insets);}复制代码总结WebView+沉迷模式下解决输入框被软键盘遮挡问题的步骤: Window.getattributes()。软输出模式设置为软输出调整大小。将视图的fitSystemWindows设置为true,我的webview中的输入框被屏蔽,因而设置webview而不是父视图。重写fitSystemWindows办法,并将insets的顶部设置为0。 窗口镶嵌依照下面3个步骤,就能够解决webview输入框梗塞的问题了,然而如果你想晓得为什么,原理是什么。你须要理解WindowInsets。咱们的沉迷式操作setSystemUiVisibility和设置fitSystemWindows属性,以及重写fitSystemWindows办法,都与WindowInsets无关。WindowInsets是利用于窗口的零碎视图的插入。例如状态栏STATUS_BAR和导航栏NAVIGATION_BAR。会被视图援用,所以咱们要做的具体操作,就是操作视图。还有一个重要的问题。不同版本的WindowInsets有肯定的差别。Android28、Android29和Android30都有肯定的差别。比方29里有一个android.graphics.Insets类,28里没有。咱们能够在29中获取而后查看top、left等四个属性,然而只能查看。是最终的,不能间接拿进去批改。不过这段WindowInsets其实能够讲很多内容,当前能够拿进去独自做一篇。上面简略介绍一下。你只须要指定咱们如何解决上述问题的原理,就是这个货色。源代码剖析在理解了WindowInsets之后,我将带您简略浏览一下setFitsSystemWindows的源代码。置信你会印象更粗浅。public void setFitsSystemWindows(boolean fitSystemWindows){setFlags(fitSystemWindows?FITS_SYSTEM_WINDOWS : 0,FITS SYSTEM WINDOWS);}复制代码它只是在这里设置了一个标记。如果你看看它的正文(我不会贴在这里),它会带你到受爱护的布尔fitsystemwindows (rectinserts)的办法(我稍后会说为什么我去这个办法)@已弃用受爱护的布尔fitSystemWindows(矩形插入){if((mprivateflags 3 & pflag 3 APPLYING INSETS)= = 0){if (insets == null) {//依据定义,Null insets曾经被应用。//此调用无奈利用插入,因为没有可利用的插入,//所以返回false。返回false}//如果咱们不在分派较新的apply insets调用的过程中,//这意味着咱们不在兼容门路中。差遣到新的//利用insets门路并从那里获取内容。尝试{mprivateflags 3 | = pf lag 3 FITTING SYSTEM _ WINDOWS;返回dispatchapplywindowsets(new window insets(insets))。is consumed();}最初{mprivateflags 3 & = ~ pflag 3 FITTING SYSTEM _ WINDOWS;}}否则{//咱们是从较新的利用插入门路调用的。//执行规范回退行为。返回fitSystemWindowsInt(insets);}}复制代码(mprivateflags 3 & pflag 3 applying inserts)= = 0这个判断前面会简略形容。你只须要晓得失常状况是执行fitSystemWindowsInt(insets)。还有fitSystemWindows叫什么?向前跳转,能够看到调用了onapplywindowsets,而onapplywindowsets是由dispatchApplyWindowInsets调用的。其实这里没必要往前看。可见这是一种分配机制。没错,这就是WindowInsets的散发机制,相似于View的事件散发机制。向前看被viewgroup称为。如前所述,这里不详细描述windowinserts,所以这里也不开展windowinserts的散发机制。你只须要先晓得有这么一个货色。public window insets dispatchapplywindowsets(window insets insets){尝试{mprivateflags 3 | = pf lag 3 APPLYING INSETS;if (mListenerInfo!= null & & mlistenerinfo . monapplywindowsetslistener!= null) {返回mlistenerinfo . monapplywindowsetslistener . onapplywindowsets(this,insets);}否则{返回onapplywindowsets(insets);}}最初{mprivateflags 3 & = ~ pflag 3 APPLYING INSETS;}}复制代码假如mPrivateFlags3为0,pflag3 applying inserts为20,0和20做OR运算,也就是20。而后判断是否存在mOnApplyWindowInsetsListener。这个听者是不是咱们在里面做过。setonapplywindowinsets listener(new onapplywindowsinsetslistener(){@笼罩ApplyWindowInsets上的公共WindowInsets(视图v,WindowInsets insets) {......返回insets}});复制代码假如没有,调用onApplyWindowInsets。ApplyWindowInsets上的公共WindowInsets(WindowInsets insets){if((mprivateflags 3 & pflag 3 FITTING SYSTEM _ WINDOWS)= = 0){//咱们不是从对fitSystemWindows的间接调用中被调用的,//调用它作为后备,以防咱们在重写它的类中//并且具备要执行的逻辑。if(fitSystemWindows(insets . getsystemwindowinsetsarrect()){返回insets . consumesystemwindowinsets();}}否则{//咱们是从对fitSystemWindows的间接调用中被调用的。if(fitSystemWindowsInt(insets . getsystemwindowinsetsarrect()){返回insets . consumesystemwindowinsets();}}返回insets}复制代码rivate flags 3 & pflag 3 fitting system _ windows是20和40的AND运算,也就是0,所以调用fitSystemWindows。而fitSystemWindows(mprivateflags 3 & pflag 3 applying inserts)= = 0)是20和20的And运算,不是0,所以调用fitSystemWindowsInt。在剖析的这一点上,咱们须要联合下面的思路来解决bug。事实上,咱们须要获取rectinserts参数并批改它的top。setonapplywindowinsets listener(new onapplywindowsinsetslistener(){@笼罩ApplyWindowInsets上的公共WindowInsets(视图v,WindowInsets insets) {......返回insets}});复制代码setOnApplyWindowInsetsListener回调中的Insets能够失去类android.graphics.Insets,然而只能看到top是什么,没有方法批改。当然,你能够看看下面是什么,而后像我下面那样设置,边距。params . top margin =-top; ...
计算机存储档次简析引言计算机的存储器层级构造是越凑近CPU和CPU关系越亲密价格越高容量越小,咱们常见的存储器有这几种,速度从快到慢的排序是:寄存器 -> 高速缓存 -> 内存 -> 内部存储器,这一节则针对这几个存储层级进行介绍。 介绍完这几个常见的存储层级组件之后会介绍对于转译后备缓冲区,页面缓存,缓冲区缓存和Linux一些不常见也简直不应用的调优参数。 存储组件介绍首先咱们来看看不同存储档次的介绍,包含下面提到的寄存器,高速缓存,内存以及他们三者之间的关系。 咱们从整体上看一下存储层次结构图: 留神这些参数放到当初都是比拟老的了,咱们只须要简略了解从左到右速度由最快到快到慢到最慢的递进。高速缓存:高速缓存是位于CPU与主内存间的一种容量较小但速度很高的存储器,当内存的数据被读取之后,数据不会间接进入寄存器而是先在高速缓存进行存储,所以读取的大小取决于缓存块的大小,读取速度取决于不同层级高速缓存的容量。 高速缓存的执行步骤如下: 依据指令把数据读取到寄存器。寄存器进行计算操作把运算后果传输给内存在下面的三个步骤中寄存器是根本没有传输耗费的,然而内存的传输就绝对于寄存器来说就慢不少了,同时整个运算的瓶颈也是内存的传输速度,所以高速缓存就是用来解决寄存器和内存之间的微小差别的。 高速缓存分为L1,L2,L3,在讲述理论知识之前,这里先举一个形象一点的例子不便了解: L1 cache:就如同须要工具在咱们的腰带上,能够随时取用,所以要获取它的步骤最简略也最快L2 cache:就如同须要的工具放到工具箱外面,咱们如果须要获取,要先关上工具箱而后把工具箱的工具挂到腰上能力应用,为什么不能从工具箱取出来再放回去呢?其实思考一下如果你须要频繁应用那得多累呀。另外工具箱尽管比腰上的空间大一点,然而也没有大很多,所以L2 cache 没有比L1 cache大多少。L3 cache:L3相比L1和L2要大十分多,相当于一个仓库,咱们获取数据须要本人走到仓库去找工具箱而后放到身边,而后再像是下面那样执行一次,尽管仓库容积很大,然而须要操作的步骤最多,工夫开销也最大。L1 cache上面是L2 cache,L2上面是 L3 cache,能够看到L2和L3都有跟L1 cache一样的问题,要加锁,同步,并且L2比L1慢,L3比L2慢. 咱们假如须要读取缓存块是10个字节,高速缓存为50个字节,R0、R1的寄存器总计为20个字节,当R1须要读取某个地址的数据时,在第一次读取数据的时候将10字节先加载到高速缓存,而后再由高速缓存传输到寄存器,此时R0有10字节的数据,如果下次还须要读取10个字节,同样因为高速缓存发现缓存中有雷同数据,则间接从高速缓存读取10个字节到R1中。 那么如果此时R0数据被改写会怎么办?首先改写寄存器值之后,会同时改写高速缓存的值,此时如果内存进来缓存块数据,在高速缓存中会先标记这些值,而后高速缓存会在某一个时刻把改写的数据同步到内存中。 如果高速缓存有余的状况下零碎会产生什么状况?首先高速缓存会依据一些缓存淘汰机制淘汰末端起码应用的高速缓存,然而如果高速缓存的“变脏”速度很快并且高速缓存的容量总是有余的状况下,会产生内存频繁写入高速缓存并且一直变动高速缓存的状况,此时就会呈现可感知的零碎抖动。 留神本文探讨的内容全副为回写,改写的形式分为直写和回写,回写在高速缓存中存在肯定的提早,利用工夫积攒的形式定时改写的形式进行内存的同步刷新,而直写的形式则会在高速缓存扭转的那一刻立即改写内存的值。那么如何掂量拜访的局限性呢? 简直所有的程序都能够分为上面两种状况: 工夫局限性:在肯定的工夫内缓存可能被拜访一次,然而能够格一小段时间再一次拜访,常见的状况是一个循环中一直取值。空间局限性:拜访一段数据的同时还须要拜访它周边的数据状况,有点相似磁盘的预读机制。如果一个过程能够掂量并且把控好下面两个点,那么根本能够认为是一款优良的程序,然而现实情况往往不是如此。 寄存器:寄存器包含指令寄存器(IR)和程序计数器(PC),它属于中央处理器的组成部分,寄存器蕴含指令寄存器好转程序计数器,另外在对于加减乘除的操作还包含累加器进行累加操作。ARM走的是简略指令集不同,而X86走简单指令集,尽管X86从当初来看是走到了止境,然而仍然发光发热并且占据市场主导地位。简单指令集会蕴含十分多的寄存器实现简单运算,比方上面一些寄存器: 通用寄存器标记寄存器指令寄存器当然寄存器的局部设计底层的硬件和电路原理能力理解,作者自身水都没有就不来献丑了,如果有感兴趣能够针对寄存器作为深刻X86架构的入口。内存:内存不仅仅是咱们熟知的电脑内存,从狭义上来说还包含只读存储,随机存储和高速缓存存储。 这里可能会有疑难,为什么内存应用的最多却不如寄存器和高速缓存呢?那是因为内存不仅仅须要和CPU通信还须要和其余的控制器和硬件打交道,同时如果内存吃紧的时候CPU还须要期待内存传输,当然这也能够反过来解释为什么须要高速缓存和寄存器。 内存除了下面提到的这一点起因还有一个起因是主板的总线带宽是有,并且同样共享给各路应用,比方南桥和其余的一些外接设备等等,同时总线也是须要抢占的,并不是分片应用。 其余补充和存储档次无关的内容之外在存储档次种还存在一些比拟非凡的缓存,比方转译后备缓冲区和页面缓存, 转译后备缓冲区上面的内容来自百科的解释: 转译后备缓冲器(英语:Translation Lookaside Buffer,首字母缩略字:TLB),通常也被称为页表缓存、转址旁路缓存,为CPU的一种缓存,由内存治理单元用于改良虚拟地址到物理地址的转译速度。目前所有的桌面型及服务器型处理器(如 x86)皆应用TLB。TLB具备固定数目的空间槽,用于寄存将虚构地址映射至物理地址的标签页表条目。为典型的联合存储(content-addressable memory,首字母缩略字:CAM)。其搜寻关键字为虚拟内存地址,其搜寻后果为物理地址。如果申请的虚拟地址在TLB中存在,CAM 将给出一个十分疾速的匹配后果,之后就能够应用失去的物理地址拜访存储器。如果申请的虚拟地址不在 TLB 中,就会应用标签页表进行虚实地址转换,而标签页表的访问速度比TLB慢很多。有些零碎容许标签页表被替换到次级存储器,那么虚实地址转换可能要花十分长的工夫。 过程如果想要拜访非凡的数据,能够通过上面提到的形式拜访逻辑地址: 对照物理页表通过查表的形式把虚拟地址转物理地址通过拜访对应的物理地址寻找理论的物理地址如果你是C语言置信应该挺相熟的,没错这里的操作相似一个二级指针的拜访操作,能够看到如果想要高速缓存发挥作用必须是一级指针的查找才有意义。然而二级指针的查找是没有太大意义的。 所以TLB的作用就是这么来的,转译后备缓冲器说白了就是用于减速虚拟地址到物理地址转化的一块非凡空间。目标是为了进步多级嵌套映射查找的速度。 页面缓存留神下面提到的内容是页表缓存,这里是页面缓存。 页面缓存的作用是什么呢?咱们都晓得内部的硬件存储速度是最为迟缓的,通常应用程序操作硬盘中的数据都是事后把数据加载到内存再进行操作,然而数据并不是间接从磁盘拷贝到内存的,而是在内存和内部存储设备之间多了一层页面缓存。页面缓存的读取步骤如下: 过程读取磁盘文本数据,寻找到相干数据之后将内容加载到页面缓存把页面缓存的内容复制到内存中,此时物理数据和内存以及页面缓存数据统一。如果须要改写文件文本数据,首先会告诉页面缓存标记本人为“脏页”。如果内存不足则空出闲暇的页面缓存给内存应用。如果页面缓存和内存都有余就须要刷新“脏页”空出空间给内存持续应用。通常状况下页面缓存会定期刷新缓存回写到磁盘中保持数据同步。另外须要留神如果页面缓存始终没有过程拜访或者应用,页面缓存会始终“收缩”,另外如果页面缓存和内存始终不够用,就会一直的回写脏页并且产生性能抖动问题。 通过这一点咱们也能够晓得为什么不倡议电脑开很多的应用程序。因为如果如果产生页面缓存回收会产生操作系统用户能够感知的抖动问题。 缓冲区缓存缓冲区缓存很容易和页面缓存搞混,咱们只须要简略了解是对原始磁盘块的长期存储,也就是用来缓存磁盘的数据,通常呈现在设施文件直连内部的存储设备,比方咱们的U盘读写和外接磁盘的读写等等,这些读写通过缓存区缓存进行治理。 须要留神缓冲区缓存通常不会特地大(20MB 左右),这样内核就能够把扩散的写集中起来,对立优化磁盘的写入,比方能够把屡次小的写合并成单次大的写等等。 Linux中调优参数理解下面各个组件的内容和细节之后,咱们来看几个简略的Linux调优参数。 回写周期:回写周期能够通过sysctl 的vm.dirty_writeback_centisecs 参数调整,然而留神这个值的单位比拟非凡,厘秒,这个参数默认设置为500,也就是5秒进行一次回写。 厘秒(英文:centisecond,符号cs),1厘秒 = 100分之1秒。当然除非为了试验理解否则不要把这个值设置为0. 除了这个参数之外,还有个百分比的参数,当脏页的数量超过百分比之后就会触发脏页回写的操作避免性能激烈抖动,上面案例的10代表了10%。 上面是这个参数的内容: vm.dirty_backgroud_ratio = 10另外如果想要应用字节的模式管制这个阈值,能够通过参数vm.dirty_background_bytes制订,如果这个参数为0则代表不开启这个配置。 当然脏页不是容许始终存在的,如果脏页积攒到肯定的量的时候,能够通过vm.dirty_ratio管制达到此百分比只会会阻塞用户过程并且把所有的脏页回写。 ...
https://www.cnblogs.com/wqbin/p/11142873.html
前言俗话说,要想富,先修路。国家修了大大小小很多的路线,有乡间小路,有省道,有国道,然而仍然没有解决人们的出行难题,路线限速,路线简单找不到路,车辆拥挤。于是,国家建筑了高速公路。高速公路笔挺宽敞,最高能够开到120km/s,并且不必放心行人平安问题,大家开车去较远的中央时都会抉择高速公路出行。 总线在主板上的各个部件传送电信号0/1时,都是由一根线作为媒介传输的,随着器件越来越多,器件之间的连线变得原来越简单,人们为了改良这种扩散连贯,创造了总线连贯形式,有一根总线贯通CPU,主存,输入输出设施。使得所有电信号通过一条线传输数据,达到简化的目标。 单总线构造单总线构造将CPU、内存、I/O设施连到一组总线上,容许相互之间间接替换信息须要留神的是,单总线并不是只有一根信号线,系统总线按传送信息的不同可细分为地址总线,数据总线和管制总线。每个总线起到传输不同品种的数据的作用。数据总线用来传输各性能部件之间的数据信息,其位数与机器字长、存储字长无关。地址总线用来指出数据所在地址。管制总线传输的是各种管制和状态信息。 双总线结构双总线结构有两条总线,一条是内存总线,连贯CPU、内存和通道。一条是I/O总线,用于在多个设施与通道之间传送数据。因为I/O设施绝对于主存是低速的,将低速I/O设施从总线中分离出来,实现了主存传输与I/O传输的拆散。通道:通道是具备非凡性能的处理器,能对I/O设施进行对立治理。 三总线结构三总线结构比双总线结构多加一条DMA总线,DMA(Direct Memory Access)又称间接内存拜访,CPU向DMA接口收回读/写命令,并指明内存地址,磁盘地址,独写数据量等参数。DMA控制器自动控制磁盘与储存的数据读写。DMA总线用于内存与高速外设磁盘之间间接传送数据,进步了数据吞吐量。 总线仲裁一条总线同一时刻只能有一条数据在上边传输,为了解决多个设施同时通过总线发送数据的问题,创造了总线仲裁形式,只有取得了总线控制权的设施,能力开始传送数据。取得总线控制权的设施称为主设施,被主设施拜访的设施,只能响应主设施的各种总线命令称为从设施。抉择哪一个设施成为主设施成为总线仲裁。总线仲裁形式可分为集中仲裁形式和散布仲裁形式两种。集中仲裁形式就是总线管制逻辑集中于一个设施中,如CPU。将所有的总线申请集中起来,利用一个特定的裁决算法进行裁决。散布仲裁形式不须要地方仲裁器,每个潜在的模块都有本人的仲裁号和仲裁器。当他们有总线申请时,就会把他们各自惟一的仲裁号发送到共享的仲裁总线上,每个仲裁器从仲裁总线上失去的仲裁号与本人的仲裁号进行比拟。若仲裁总线上的仲裁号优先级高,则它的总线申请不予响应,并撤销他的仲裁号。仲裁号最高的那个将申请到总线使用权。
算这个寒假把往年学的局部内容总结一下,就先从CSAPP开始吧
文章起源 cxuan 的本人公众号:计算机组成原理之总线设计 公众号很多硬核文章,跪求大家关注~~~ 上面开始正题。 咱们晓得,计算机是由五大部件组成的:运算器、存储器、控制器、输出设施和输出设备,这个概念比拟形象,简略一点来说就是 CPU 蕴含运算器和控制器,存储器也就指的是内存,而输入输出设施别离指的是键盘和显示器。计算机这几个部件之间是须要独特合作实现信息处理的,那么,这几大部件之间如何进行通信呢?靠的是系统总线,这也是咱们这篇文章探讨的重点。 意识总线总线是将两个计算机或者多个性能单元连贯在一起并容许它们相互交换数据的一种通路。总线还能够将计算机和外部设备连贯在一起。总线是计算机系统十分重要的组成部分。对于须要晓得上面这几个概念。 总线宽度:个别用并行数据通路的数量来定义总线的宽度,个别总线的宽度有 8 位、16 位、32 位、64 位,咱们当初最罕用的就是 64 位总线,一条 64 位宽的总线一次可能传输 64 位也就是 8 个字节信息。带宽:带宽是掂量数据在总线上传输速率的一项指标。在保持数据传输速率不变的状况下进步并行通路的数量,能够进步总线的带宽。提早:提早是从收回数据传输申请到理论数据传输的工夫距离。总线分类上面咱们次要介绍两种总线,一种是片内总线,一种是系统总线,片内总线个别指的是 CPU 芯片外部、寄存器和寄存器之间、寄存器和算术单元 ALU 之间的连贯。 而系统总线次要是指 CPU 和内存、内存和 IO 设施、CPU 和 IO 设施等各大部件的信息传输介质。系统总线依照传输信息的不同次要分为上面三类。 地址线数据线控制线 上面咱们就来具体理解一下这三类总线 地址总线地址总线次要用于传输源数据或者目标数据在主存单元中的地址。 CPU 通过地址总线来指定存储单元的地位的,地址总线上能传送多少信息,CPU 就能够对多少个存储单元进行寻址。 上图中 CPU 和内存两头信息替换通过了 10 条地址总线,每一条线可能传递的数据都是 0 或 1 ,所以上图一次 CPU 和内存传递的数据是 2 的十次方。 所以,如果 CPU 有 N 条地址总线,那么能够说这个地址总线的宽度是 N 。这样 CPU 能够寻找 2 的 N 次方个内存单元。 数据总线数据线顾名思义就是一次传递数据的位数,数据总线的位数就是数据总线宽度。 ...
一、编译流程预处理:依据以字符#结尾的命令,批改原始的C程序。例如:第一行中的#include xxx命令通知预处理器要读取头文件的内容,并把它直接插入程序文本中。最终失去.i文件编译:将文本文件.i翻译成文本文件.s,它蕴含汇编语言程序汇编:将.s文件翻译成机器语言指令,并打包成可重定位的目标程序,后果生成到.o文件中链接:链接合并多个.o文件,最终失去可执行程序 二、运行unix零碎运行流程: 2.1 从磁盘加载可执行文件到主存利用间接存储器存取技术,数据能够不通过处理器间接从磁盘加载到主存(DRAM)中 2.2 执行并输入指标文件中的代码和数据被加载到主存中之后,处理器就开始执行程序中main程序中的机器语言指令,再从寄存器文件中复制到显示设施,最终显示在屏幕上
1. CPU实现的形象逻辑图 2. 建设数据通路:指令+运算=CPU1. 什么是指令咱们撰写的代码,是怎么变成一条条的机器可能了解的指令的,以及是依照什么样的程序运行的2. 什么是计算数据的二进制示意是怎么样的,咱们执行的加法和乘法又是通过什么样的电路来实现的3. 什么是指令周期永不停歇的”Fetch - Decode - Execut”循环,就是一个指令周期分为几个步骤 Fetch(获得指令)Decode(指令编译)Execut(执行指令) 4. 什么是机器周期5. 什么是时钟周期6. 三者之间的关系举个例子 指令周期 CPU周期1 时钟周期1时钟周期2CPU周期2CPU周期3一个指令周期,蕴含多个CPU周期,而一个CPU周期蕴含多个时钟周期 7. 什么叫建设数据通路由两局部组成 操作元件存储元件8. CPU所需的硬件电路ALU这类的组合逻辑电路用来存储数据的锁存器和D触发器电路 通过D触发器实现存储性能用例实现PC寄存器的计数器电路 PC寄存器,也叫程序计数器用例解码和寻址的译码器电路 读写数据所须要的译码器 2-1选择器3-8译码器译码器的实质 从输出的多个位的信号中,依据肯定的开关和电路组合,抉择出本人想要的信号3. 汇总脑图
计算机实践模型五大外围组成部分:控制器(Control):调度程序、数据、地址,协调计算机各局部工作及内存与外设的拜访。运算器(Datapath):对数据进行各种算术运算和逻辑运算。存储器(Memory):存储程序、数据和各种信号、命令等信息。输出(Input system):输出设施是计算机的重要组成部分,输出设施与输出设备合你为外部设备,简称外设,输出设施的作用是将程序、原始数据、文字、字符、管制命令或现场采集的数据等信息输出到计算机。常见的输出设施有键盘、鼠标器、光电输出机、磁带机、磁盘 机、光盘机等。输入(Output system):输出设备与输出设施同样是计算机的重要组成部分,它把外算 机的两头后果或最初后果、机内的各种数据符号及文字或各种管制信号等信息输入进去。微机 罕用的输出设备有显示终端CRT、打印机、激光印字机、绘图仪及磁带、光盘机等。下图-冯诺依曼计算机模型图: 当初计算机实践模型运行原理冯.诺依曼计算机模型运行原理: 1、古代计算机模型是基于-冯诺依曼计算机模型;计算机在运行时,先从内存中取出第一条指令,通过控制器的译码,按指令的要求,从存储器中取出数据到计算器外面进行指定的运算和逻辑操作等加工,而后再按地址把后果送到内存(存储器)中去。接下来,而后再从存储器外面取出第二条指令,在控制器的指挥下实现规定操作。依此进行上来。直至遇到进行的程序指令。2、程序与数据一样是存储到咱们的内存存储器当中,按程序编排的程序,一步一步地取出指令,主动地实现指令规定的操作是计算机最根本的工作模型。这一原理最后是由美籍匈牙利数学家冯.诺依曼于1945年提 进去的,故称为冯.诺依曼计算机模型。 简而言之:计算机的工作模型就是通过控制器从存储器外面取数据,而后加载到计算器外面进行计算,计算结束之后,再次存储到存储器外面。 当初计算机根本硬件构造 通过下面的计算机根本硬件构造咱们晓得: 1、上图中cpu就是计算器/运算器;2、存储器就是指代咱们的内存条跟磁盘,就是咱们下面的拓展槽。 3、控制器就是咱们的罕用的USB控制器:鼠标,键盘。 下面是计算机各个硬件的组成单元,各个硬件的组成单元是通过什么设施什么样的形式取进行交互通信呢?晓得计算即的人能够晓得咱们的计算机上都会有一块大主板:咱们各个cpu或者内存条、或者磁盘都是插在主板上的,然而每个硬件都是独立存在的。那么他们之间通过什么形式进行通信呢?通过下面硬件图咱们能够晓得,他们是通过I/O总线进行通信的。冯.诺依曼计算机模型外面次要有两个比拟重要的货色:计算器cpu跟存储器:内存条;内存条会存储咱们运算的数据或者程序指令,而计算器cpu会通过I/O总线从咱们的存储器外面获取数据指令,而后load到咱们cpu本人的缓存外面。 当初计算机根本硬件存在的问题咱们的cpu是遵循摩尔定律的,其计算运行速度是十分快的,而咱们的磁盘,内存条跟磁盘I/O读取速度很慢 1、下面能够看到咱们的CPU具备3级缓存;并且其对应的基准速度是1.80GHZ。 个别咱们的内存读取速度是只有几百M;因为咱们cpu进行计算的话,其数据都是从内存外面获取的,所以cpu的计算速度远远大于从存储器外面读取数据;所以间接从内存外面读取数据也是十分满的。 2、从下面咱们晓得,cpu从存储器外面读取数据须要通过咱们的I/O总线进行数据交互;I/O总线是所有的控制器,所有硬件之间的交互通信都是须要通过I/O总线的,而I/O总线又是具备肯定带宽的。就相似与一个马路上须要跑很多车辆会拥挤起因;所以I/O总线的带宽也是限度了间接从内存外面读取速度是比较慢的。所以这个也是咱们当初计算机引入缓存的起因。 计算机缓存复制形式首先,计算器通过I/O总线将存储器外面的数据加载到L3级缓存,而后从L3级别缓存加载到L2级别缓存,而后再加载到L1级别缓存。而后L1缓存会将其复制到咱们的寄存器外面去。寄存器再取出来放到计算单元外面去计算。计算完之后再写到寄存器,而后逐级同步到各个缓存:L1->L2->L3,至于L3什么时候写回到内存是不确定的,这个须要看咱们的cpu是否有闲暇? 那咱们有没有方法让计算出来的后果立刻刷新到内存。这里就波及到咱们一个很大的概念:缓存一致性协定。所以当初的话咱们总结出存储数据的单元有:寄存器、多级缓存、内存。