为什么我的电脑这么慢?

大约一年前我入手了一台小电脑,是联想的奥运纪念版,少说都是07年的东西,硬盘只有80G,但是CPU是Intel酷睿双核的1.6GHz,内存原主加到1G,我自己装了XP和Debian,所以用起来才凑合。但是近来(其实是一段时间以前),我感觉电脑似乎比原来刚买的时候要慢了一些(其实不少),主要体现为:foobar播放无损时卡顿或者没声音,firefox反应极其缓慢,打字法延迟严重等。为了知道怎么修,我稍微分析了一下原因:


一、什么是慢?

到底计算机表现成什么状态让用户(我)觉得它慢呢?

事实上,人操作计算机的任何动作都需要执行运算(包括仅仅是动了一下鼠标),这都要占用CPU资源,因此从本质上讲,再快的计算机都不能马上完成任务。然而,人是慢的,因此计算机有相对足够多的时间来反应。所谓的慢应该由人类的反应速度来决定。仅仅作为一种参考,一般电影的帧率是24fps,也就是人在再慢的情况下就会感受到延时,也就约莫是41.67ms,对于一个1GHz的CPU来讲,是41.67e6个时钟周期,粗略估算,能执行4kw条指令。当用户输入一项动作的时候,除非这项动作真的需要4kw条指令来执行,否则计算机应该就能在人类能感受到的时间范围内完成工作(而事实上,需要这么多条指令来完成的一项动作是有限的),然而我的小电脑反应比它所应该反应的要慢很多,仅仅是打字就已经会有一段延时,这显然是不合理的。



二、为什么会慢?

既然知道慢是由计算机的运算延时引起的,那引起这些本不应该产生的延时的来源是什么呢?

显然,CPU在通电时刻永远是在进行运算的,也就是说它总会在做些什么,要使得在特定的时钟周期内做更少的事情,这个原因是多层面的,我从上而下地分析产生延时的原因。


1 应用程序的设计缺陷

应用程序的结构远比想象中的要复杂。编写一个简单的应用程序是简单的,但是编写一个有优良用户体验的应用程序是一门学问(所以我不喜欢GUI sign)。因此应用程序的设计缺陷明显会带来用户不能接受的体验。比如说一些应用程序(有GUI的)实际上是会有大量IO访问的倾向的,而其中对硬盘和网络的访问的延时,人类能够很清楚地感觉地到。而又简单起见,开发者又只用单线程很线性地解决问题,结果是当程序阻塞到IO读写的时候,前台面板就会假死,而实际的原因却是线程/进程被阻塞从而调度器将其放入了等待队列,而并不是真的死去,从而引起延时或者失去响应的假象。

但是随着一些程序框架的发展和程序员能力的提高,这种问题越来越少见(但是我就碰到过,ActivePerl的ppm gui,典型的阻塞死),而我电脑的情况是针对每一个进程都出现的,因此显然和这个原因无关,这个问题也不是本文讨论的重点。


2 调度器的缺陷

调度器的工作是进程调度(真是废话)。原来一开始接触到这个概念的时候,我认为不就是个分蛋糕的问题么,用得着这么复杂吗?后来学进去了以后发现调度器最难设计的地方是通用性。一个OS是一个平台,谁也不能也不会规定这个OS上只能运行这样那样的程序。然而程序是多种多样的,针对CPU密集型、IO密集型和实时进程所用的调度策略就不尽相同,因此,Linux发展了这么多年,进程调度依然是其中复杂且潜力大的模块。

对于一个调度器的设计,其本质是对调度器性能的多种指标的权衡。然而调度器的一些权衡策略不合理时,配之以应用程序恰当的策略,就能从调度器手上骗取到更多的CPU时间,从而让其他进程执行更少的指令,这显然给了某个应用程序一种途径干预其他应用程序的运行。

比如说Linux的历史上有个很经典的进程调度器叫做O(1)调度器,以能在常数时间内完成一次进程调度著称,让Linux的进程调度自2.4以来有质的飞跃,这个优越性让这个调度器在一段时间内广受称赞。它在2.5时候开发,却在2.6.23就遭到淘汰。这个调度器有很多好处,然而又4个缺陷足以让O(1)被取缔:

  1. Linux用nice值表示进程的优先级,值越高,优先级越低。而假设有100个nice值为0的同类进程参与调度,那么他们显然都能得到同样长度的时间片,而调度器在其间可能需要1%的时间为代价,这应该是可以接受的;然而如果这100个进程的nice值都是10,那么虽然他们还都可以获得相同长度的时间片,然而调度器的代价却明显增加,打个比方,10%。也就是说,在同等的结果下,CPU多花了9倍的时间却没有做任何有意义的事情。由此可知,nice值得调整可能会引起上下文切换的代价增加。
  2. 对于进程间的关系,如果一个进程A的nice值是-9,那么它可能会获得100ms的时间片/调度周期,另一个进程B的nice值是-8,按道理它会获得95ms的时间片/调度周期。显然,在这个情况下,这两个进程的时间片是差不多的,表现出来A和B运行的时间约莫是1:1。然而,如果A的nice值是9而B的是10,那么A就只能获得10ms而B是5ms,这样A就比B多运行一倍的时间,然而它们之间的nice值差确依然是1。也就是说,同等的nice值差带来的调度效果和nice值的基准有关。
  3. 这一项相对不那么重要。最小时间片和CPU执行能力有关,因而越慢的CPU要多花时间来完成一个调度周期。
  4. 这一项则最为重要也偏向是本文的重点:O(1)的时间可以被骗取。O(1)有一项优待IO密集型进程的调度机制,就是允许调度重排,也就是允许IO密集型的进程重新插入调度队列等待调度,即使是当个周期调度进来的时间片已经用完了。那O(1)怎么区分进程的IO密集还是CPU密集呢?这需要O(1)有记账机制,如果一个进程在它的时间片中有一定时间在休眠,则这个进程就被认定为IO密集的。这就引入了一个漏洞。如果一个进程有意地休眠-唤醒-休眠-唤醒,如果再加以期望的启动方式,它就能获得一个最大时间片(比方说100ms)的调度,并且还能在一个调度周期中多次插入调度队列,从而极大地影响其他进程的运行。

根据第4点,如果我能用这个策略+一个不做任何事情的循环,我就能恶意变相抢占其他进程的时间片而不做任何事情。

因此,早在2.6.23,Linux的调度器就换成了CFS。这一个调度器的缺陷依然有且很明显,我估计以后还有取代者,我就不对其做详细分析了。


另外再有一点,如果称IO密集是软实时的话,那么硬实时就是另外一项要求,一个领域了。这一项随着半导体发展,其需求越来越小:CPU快了,RAM也增大了,就连实时进程也能像一般进程一样参与调度。但是在一些应用场景下(比如说一个对时间相应要求短且苛刻的应用), 实时进程依然需要被区分。而从我的经验来看,实时任务负载往往都是脉冲式的:CPU在一定时间内等待数据或执行命令到来,这一段时间内实时进程要不是休眠,要不是无所事事,总之不会有任何有意义的行为;而当数据和执行命令到来以后,工作量会顿时爆发性地增长,并且不可中断,根据应用,伴随着可能很可观的运算量(比如2D+时间轴的实时视频处理,Steam和Nvidia就合作搞了个实时H264高清视频流传输到Shield玩PC游戏,这个技术估计要用GPU辅助,吃功率)。这种特性的任务,有可能在通用调度器下并不能很好地完成工作,因而需要特定的实时调度器。由于我的电脑不是硬实时系统,因此我的问题显然不会是这一小块引起的,也省得脑筋想。


3 恶意/设计不良的内核模块/驱动

这一块出问题,用户能看到各种各样有趣的OS异常,不要说调度缓慢,死机蓝屏那也是随便发生的事情。然而,显然我的情况没这么严重,仅仅是太慢而已,从这个方面也能探讨出让计算机变慢的原因。

一个内核模块运行在内核空间,而内核空间的优先级高于用户空间,因此,用户空间的程序可以被内核抢占而相反则不可以。对于一个恶意或者设计不良的内核模块,如果它能够向内核插入一个任务,使得内核长期驻留在内核空间,那么用户空间则会失去响应(一段时间地)。

驱动本质上也是内核模块,但它更特殊的地方在于能够支配硬件资源,而对于驱动,其更加特殊的权限在于能够引发并且处理中断。如果一个恶意或者设计不良的驱动长期驻留在irq中不退出,又或者向下半部机制安插不安全或者不合理的函数调用或者延迟,那么在用户空间来看,CPU就被驻留在内核空间,同样使得应用程序失去运行时间。

然而,随着OS的smp化,即使是一个CPU被塞在内核空间里了,还能有另外至少一个CPU完成用户空间的工作(在内核鲁棒性足够强的情况下),因而这个会在单核CPU带来灭顶之灾的问题不至于为用户界面带来十分大的影响。我的小电脑好歹也是个双核的,因此我推断主要原因不再这里(至少在Debian下)。


4 page swap

终于到这个大头了,我的经验估计,一个健康的OS的90%以上的卡顿都是由这个原因造成的。

所谓page swap就是硬盘映射到了一部分vm上,当这个page需要/不被需要时的换入/换出机制,用来制造进程独占4G内存的假象。但是假象总归是假象,根据IO的金字塔结构,CPU只允许直接访问内存(实际上来讲这是不严谨的,一般而言是错的),因此换出到硬盘的数据必须换入到主存才能进行读写,而硬盘是相当慢的,一般的机械硬盘的读写速度是20MB/s,因此,人能反映0.833MB以上的硬盘读写间隔,而又硬盘换出必然是换入引起的,在内存紧张的情况下,约莫0.42MB的内容需要交换的时候,人就会觉得卡顿。在x86的机器下,4KB是一个page,因此如果需要一次性交换100个page左右的内存就足够影响用户体验。

而page在有限的内存和近似无限的硬盘空间中是如何被管理的呢?在OS里面,有一个大模块MMU负责这部分的管理,而且这需要硬件的辅助,一个page的换入换出大致上是由以下流程完成的:

    page fault触发源触发page fault(比如对换出页的访问,或者对新页的申请等)

->进入page fault异常处理程序

->page fault异常处理程序根据一定算法来决定换出的page(一般而言Clock算法或者其变种)

->swap page,此时进程被阻塞

->page swap完成后,进程重新开始未完成任务,此间不需要应用程序干预,实现对应用程序透明的mm

而现在的应用程序需要多少内存空间简直是没个尽头,比如说firefox占个300~400MB内存是常态,在我1G内存的情况下,很难再能有充裕内存,因而再多开个altium designer, foobar2000,几个开发环境,电脑肯定是卡得要死了,这个时候明显就会引发大量的page swap,如果firefox被全部换出,当需要的时候要换入,那么基本上需要swap 600MB的数据,因此要完成全部swap则约莫需要30s的时间,可见,page swap实际上是一个常见的,频发的,而且代价特别大的一个引起计算延时的来源。


三、怎么能不慢?

在二中大致整理了在用户空间引起计算机缓慢的原因,那么针对地,怎么解决相对应的原因引起的延时呢?


1 用久经考验的稳定版内核

有时候随时更新系统并不是一个好的选择,在一个内核下正常运行的程序,在另一个程序下可能得不到对应好的表现(当然如果是windows那就没得选了),因此,对于久经社区考验的稳定版内核是一般任务的首选。而对于一般Linux用户而言,太新版本的内核可能会有不稳定的表现(尽管从版本号来看确实是稳定版本),应该尽量避免;而尽管是有一定开发内核模块需求的用户,也应该尽量避免过新版本,从而避免常用接口的改变和内核行为和预想中不吻合。


2 用可信来源的模块/软件包

可信来源有良好的bug汇报途径,而且一般情况下不会有设计不良的情况出现。


3 加!内!存!

page swap是硬伤,而且是必要的,因此从根本缓解这个问题的方法有两个:一是别开这么多软件,而是多加些内存(翻个倍什么的)。


四、我的电脑是什么问题?

最后我发现,当电脑特别慢的时候CPU和RAM的频率都往下掉了,而电脑底部十分烫,因而我推测这么慢的根本原因是:过热了。而过热的根本原因是风扇停转了,因此当我把新风扇换上去以后,事情一切都正常了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值