书吧达 > 四合院开局四八,八岁带妹逃荒 > 第687章 看不见的沙漏!

第687章 看不见的沙漏!


`KERNEL  PANIC  -  OUT  OF  MEMORY`

血红色的屏幕,如同地狱的判词,瞬间将整个实验室,从完美的乌托邦,拉回了残酷的现实。

“内存耗尽?”

“怎么可能!怎么会内存耗尽!”

黄建功猛地从椅子上弹了起来,不敢相信自己的眼睛。

内核恐慌!

这个他们以为,在解决了“堆栈隔离”问题后,就再也不会见到的噩梦,竟然以一种全新的,更加诡异的方式,再次降临!

而且,错误的原因,是“内存耗尽”!

这怎么可能?

他们的系统,现在总共就运行了五个极其简单的任务。

内核本身,加上五个任务的堆栈,所占用的内存,加起来也不到100KB。

而“盘古之心”拥有整整4MB的物理内存!

这就好像,一个拥有着巨大湖泊的人,却被告知,他因为缺水而渴死了!

这完全不符合逻辑!

“快!查!”黄建功对着整个实验室,发出了嘶吼,“查明原因!是不是硬件出了问题?内存条坏了吗?”

周老立刻带着人,冲向了硬件检测台,对“盘古之心”的内存模块,进行紧急检测。

而钱学敏和孙立国,则第一时间,冲到了主控台前,开始疯狂地,翻阅系统崩溃前,留下的最后几页日志。

试图从那片数据的汪洋中,找到一丝线索。

几分钟后。

周老脸色凝重地走了回来。

“内存,没有问题。”

“我们做了最高强度的读写测试,4MB的每一个字节,都完好无损。”

这个消息,让所有人的心,沉得更深了。

硬件没问题。

那就意味着,问题,百分之百,又出在了他们引以为傲的,“天枢”内核上!

“建功,你看这里!”

钱学敏突然指着屏幕上的一片数据,她的声音,带着一丝不易察觉的,颤抖。

黄建功立刻凑了过去。

那是一段由内核内存管理器,在每次分配内存时,打印出的调试日志。

`[  1859.235]  kmalloc:  allocated  64  bytes  at  0x0012c800.  free_mem:  3.82  MB`

`[  1859.578]  kmalloc:  allocated  64  bytes  at  0x0012c840.  free_mem:  3.82  MB`

`...`

这些日志,记录了每一次内核为内部数据结构(比如任务控制块TCB)分配内存的动作,以及分配后,系统剩余的空闲内存大小。

刚开始,一切正常。

系统剩余内存,一直稳定在3.8MB左右。

但当黄建功将日志,快速地向后翻动,翻到接近系统崩溃的那个时间点时。

他的瞳孔,猛地一缩。

`[  1860.112]  kmalloc:  allocated  64  bytes  at  0x003f8000.  free_mem:  0.12  MB`

`[  1860.455]  kmalloc:  allocated  64  bytes  at  0x003f8040.  free_mem:  0.12  MB`

`...`

`[  1861.988]  kmalloc:  allocated  64  bytes  at  0x003fffc0.  free_mem:  64  bytes`

`[  1862.331]  kmalloc:  FAILED!  Cannot  allocate  64  bytes!`

日志,清晰地,记录下了整个“死亡”的过程!

系统的空闲内存,在以一种肉眼可见的速度,被不断地蚕食!

从3.8MB,到1MB,到100KB,再到最后的几十个字节……

直到最后,当内核再次试图申请64个字节的内存时,它绝望地发现,整个内存池,已经空了。

于是,它触发了最严重的“内核恐慌”,整个系统,轰然倒塌。

“这……这到底是为什么?”一个年轻的研究员,声音发颤地问道,“我们的系统,从启动之后,就再也没有创建过新的任务。为什么内核会一直,不停地,在申请新的内存?”

是啊。

为什么?

这就像一个看不见的沙漏。

在所有人都没有察觉到的情况下,一点一点地,漏光了整个系统的生命之源。

黄建功死死地盯着那几行日志,大脑在疯狂地运转。

`kmalloc`...  `kmalloc`...  `kmalloc`...

内核在不停地分配内存。

但是,它分配了,却没有“释放”!

一个可怕的词汇,如同惊雷般,在他的脑海中炸响。

“内存泄漏(Memory  Leak)!”

当他将这个词说出口时,钱学敏的脸色,瞬间变得惨白。

她也想到了。

在计算机科学中,这是一种最常见,也最阴险的错误。

程序在运行过程中,不断地向系统申请内存,但当这些内存不再被使用时,却没有及时地,将它们归还给系统。

日积月累。

这些被“遗忘”的,无法被再次使用的内存,就像血管里的血栓,会一点一点地,堵死整个系统。

“我们在哪里泄漏了内存?”黄建功喃喃自语。

他开始疯狂地,在脑中,回顾“天枢”V0.3的每一行业务逻辑。

创建任务时,分配TCB,分配堆栈。

这都是一次性的。

之后,系统就在五个任务之间,不断地切换,调度。

切换……调度……

每一次切换,内核都需要保存当前任务的上下文……

每一次调度,内核都需要测量切换的成本,计算新的时间片……

这个过程,会产生新的内存分配吗?

黄建功的目光,猛地落在了那段关于“上下文切换成本”的日志上。

`Switch  cost:  12  us.`

`Switch  cost:  15  us.`

`Switch  cost:  73  us.`

为了计算这个成本,内核需要在切换前后,两次读取HPET的计数值。

然后,进行一次减法运算。

为了存储这两个计数值,和那个最终的差值,内核需要……临时的变量!

而这些临时变量,是存放在……

“堆栈里!”钱学敏和黄建功,几乎在同一时刻,失声喊了出来!

他们瞬间,就定位到了那个“看不见的沙漏”,到底藏在哪里!

每一次!

每一次时间中断发生时,CPU都会将当前任务的执行现场,压入内核的堆栈。

然后,跳转到中断服务程序。

中断服务程序,也就是他们的调度器,为了计算切换成本,又在内核堆栈上,定义了几个临时的变量。

当调度完成,切换到下一个用户任务时。

那些被中断压入的用户任务现场,会被正确地弹出。

但是!

他们忘了!

他们忘了去“清理”,那些在中断服务程序中,使用过的,临时的,属于内核自己的,堆栈空间!

每一次中断,内核的堆栈指针,都会因为这些被遗忘的临时变量,而向下,移动那么微不足道的,几个字节。

一次中断,几个字节。

一秒钟,一百次中断,就是几百个字节。

三十分钟……

黄建功的心,凉了半截。

他终于明白,那4MB的内存,是怎么被一点一点,耗光的了。

不是用户任务的错。

也不是内存管理器的错。

是他们自己!

是他们亲手编写的,那个被他们视为“绝对公平”的调度器,在每一次“心跳”的时候,都在为自己,挖深一点点的,坟墓!


  (https://www.shubada.com/105253/39447634.html)


1秒记住书吧达:www.shubada.com。手机版阅读网址:m.shubada.com