关于不可变操作系统的设想

2024-01-26 06:08
文章标签 操作系统 不可 设想

本文主要是介绍关于不可变操作系统的设想,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!



为什么会想到操作系统



大概一年以前,我有一个想法,就是基于不可变值实现OpenGL的渲染器。我把这个想法发到博客上了,并且在Hacker News和Reddit上得到了不少关注。还有些人甚至给我发来了邮件。

在吊床上思考了很长一段时间后,最后这个想法转移了操作系统的身上。大致是:如果操作系统是由不可变值组成的会是怎样的呢?

不可变的操作系统?世界都是一直改变的



不可变值是观察世界来说是一个非常合理的方式。作为一个观察者,你看着这个世界随着时间流逝在不停的变化。当你想要做些什么的时候,你会拍下张照片。这个照片是静止的,你愿意花多长时间去分析它都无所谓。

再回到操作系统这个话题上来。在这里唯一可变的只有一个交换操作。你会有一个叫原子(atom)这么个东西,它会指向一个不可变的值。你可以随时获取到它当前指向的不可变值。从原子这总能获取到一个完整的值,正如它名字所说的,它是个原子。你可以给它赋值,这样的话这个原子会指向另一个新的不可变值。你不能够直接修改某个值。原子应该有某些机制来保证,上次读完后没人进行更新的话,才能对它进行修改,这样的话,它会更可控些。

细心的读者会发现,我刚才说的其实就是Clojure里面的状态模型。这也正是我这个操作系统将要实现的,状态就是由一系列的不可变值组成的。

不可变的内存模型



那么,一个进程会拥有很多指向不可变值的原子,而所有这些值都是无法修改的。没错,这里我说的就是所有。你可以将字节序列存储到一个值里,不过这些字节是不可变的。位移操作?创建一个新的值来完成。要修改第四个字节?也是创建新值。

在这个模型里面,内存可以在进程间安全的进行共享。把一个不可变值传给另外一个进程有什么关系呢?没事。非常安全。这里也不需要什么保护性拷贝或者别的保护机制。只有原子本身需要保护。应该有一个机制来管理进程间原子共享,只有创建这个原子的进程可以去共享它。

创建进程几乎就没有任何开销。在Linux里面,fork操作有个非常聪明的写时复制(COW)的机制,因此fork操作一开始什么也不干,一旦这两个进程有人开始修改内存里的值的时候,才会发生拷贝操作。当然这也是有一定的开销的。但如果值是不可变的话,这就完全没有任何开销了,根本就不需要进行拷贝。不可变的就是不可变的!唯一的开销就是拷贝原子本身了,你可以使用用拷贝模式(时间复杂度是O(n)),也可以使用Linux系统的COW的机制。

如果可以进行指针运算的话就一切都完蛋了。解决方法就是对于这个操作系统上的开发语言而言,它是没有指针的。指针还会占内存,我们可不喜欢占地方的东西。我们要存储的只是值。

当然了,还可以进行许多优化。Clojure有一个transients的概念,它的意思是"当你在一个函数里创建一个值的时候,你可以对它进行修改,一旦它从函数里返回了,它就是不可变的"。因此从外面看来,函数没有修改任何范西,因为这个可变的值只是函数内部可见的。我会替你自动检测这个。我们还可以监测是否有别人引用了你的值,如果没有的话,你可以对这些值进行修改。这只是一个优化,对程序员来说完全是不可见的。

垃圾回收



一个不可变值组成的系统也是需要垃圾回收的。这些都会在系统底层来完成。

如果垃圾回收器知道所有这些值都是不可变的,那么事情就非常有意思了。一般来说,垃圾回收 器在整理老生代堆的内存碎片的时候,会暂停所有的操作(stop the world)。当所有值都不可变的时候,如果要碎片整理,你就把一个值拷贝到另一块区域,然后更新下内部的指针就好了。

还有一点,通过这种拷贝并交换指针的方式,你还可以优化内部的字节编码,而不用暂停程序的运行。假设我们发现老生代中的值X是一个map,并且它已经很久没有更新了。或话我们可以把它优化成某种结构,也就是把它拷贝到内存中另外一个地方,不过用一种不同的可能是更高效的方式来进行存储。除了内核没人知道这事,也不需要暂停程序的执行。

性能



我们一直都在努力能更好的 与硬件进行协作以提升性能。事实上就是尽可能把操作系统的C代码用硬件来实现。我有一个荒谬的想法就是让英特尔在硬件层来实现我这个操作系统,然后观众席上有人大声高喊,"我们终于可以用XXX换掉RAM内存啦!“或者类似的。我并不是一个硬件工程师。能不能用硬件来实现不可变值的垃圾回收?想想罢了。

这并不是说我自己不去做性能优化。也许这个操作系统在某些方面比传统的操作系统性能要好,因为它不需要写时复制或者保护性拷贝,它的值可以自由的共享。在处理器看来,代码也是不可变的,缓存了代码的处理器的效率可比缓存了数据的要快得多。如果CPU知道内存中的哪些数据页是不可变的话,那么一级缓存和二级缓存应该会高效得多。或许我们可以通过将数据拷贝到不同的芯片上来解决冯诺依曼体系的瓶颈问题?因为这是完全不可变的数据,你可以放心的去拷贝。不过谁知道呢,让时间来证明吧。

文件系统



这块想的不是很多。说实话我自己很少在程序中使用文件,我一般直接访问数据库。所以我想这个系统的持久层应该是一个key/value的数据库。或许像Datomic那样只能追加数据,不能修改?又或者在这个不可变系统里,文件系统也存储到一个不可变的地方?好吧,谁知道呢。


开发语言



当然是Lisp。我会为Lisp定制一种字节码格式,可能会和EDN很像。这不完全是编译后的字节码,所以字节码这个说法可能欠妥。我觉得应该用一种巧妙的编码格式来存储Lisp的抽象语法树(AST),而不仅仅是纯文本。纯文本太痛苦了。最后会有一个JIT编译器来读取这种格式,然后编译成本地的机器码。

代码当然是不可变的。因此可以放心去做热部署,原有的代码会继续运行,而新的调用会分发到新部署的代码上。

没想好应该用静态语言还是动态语言。哪个更容易实现就用哪个吧。

再强调一遍,这个系统看起来很像是Clojure的一个衍生物。我也不太确定是不是就用Clojure作为开发语言就好了(Clojure已经移植到不同的平台上了,JS,JVM,CLR)。还是那句话,谁知道呢。


这很可能是个错误的想法



这是我写的第一个操作系统。

很有可能我讲的没有一点是对的,但这也正是我实现它的原因。这只是一个研究性的项目,没有什么实际的目的,比如解决程序缺陷过多之类。我只能说,这只是一个爱好,不会像GNU那样那么专业全面。在证明这些想法可行之前,我暂时还不会考虑到什么会议上去分享它们。

这个系统还有很长的路要走,因此现在 实现的东西还不多。等我先把进程和GC这块搞完再向大家汇报进度吧。

原创文章转载请注明出处: http://it.deepinmind.com

英文原文链接



这篇关于关于不可变操作系统的设想的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/645859

相关文章

Linux操作系统 初识

在认识操作系统之前,我们首先来了解一下计算机的发展: 计算机的发展 世界上第一台计算机名叫埃尼阿克,诞生在1945年2月14日,用于军事用途。 后来因为计算机的优势和潜力巨大,计算机开始飞速发展,并产生了一个当时一直有效的定律:摩尔定律--当价格不变时,集成电路上可容纳的元器件的数目,约每隔18-24个月便会增加一倍,性能也将提升一倍。 那么相应的,计算机就会变得越来越快,越来越小型化。

MySQL脏读、不可重复读、幻读(虚读)

事务的特性: 原子性:指处于同一个事务中的多条语句是不可分割的。一致性:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。比如转账,转账前两个账户余额之和为2k,转账之后也应该是2K。隔离性:指多线程环境下,一个线程中的事务不能被其他线程中的事务打扰持久性:事务一旦提交,就应该被永久保存起来。 事务隔离性问题: 如果不考虑事务的隔离性,会出现以下问题: 脏读:指一个线程中的事务读取到

1、简述linux操作系统启动流程

1、简述linux操作系统启动流程 启动第一步--加载BIOS 当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它。这是因为BIOS中包含了CPU的相关信息、设备启动顺序信息、硬盘信息、内存信息、时钟信息、PnP特性等等。开机时将ROM中的指令映射到RAM的低地址空间,CPU读取到这些指令,硬件的健康状况进行检查,按照BIOS中设置的启

操作系统是怎么为不同的程序分配所需的内存空间的

操作系统为不同的程序分配内存空间的过程涉及多个关键步骤,确保每个程序都有其所需的内存资源,同时避免程序之间的冲突。以下是操作系统如何为程序分配内存空间的详细过程: 1. 内存管理的基础概念 虚拟内存:现代操作系统使用虚拟内存机制来为程序提供隔离的内存空间。每个程序运行在其独立的虚拟地址空间中,这使得程序间的内存互不干扰。物理内存:实际的 RAM(随机存取存储器),由操作系统和硬件共同管理。虚拟

操作系统安全保护

操作系统安全概述 概念:满足安全策略要求,具有响应安全机制及安全功符合特定安全标准,在一定约束条件下 能抵御常见网络安全威胁,保障自身安全运行及资源安全 安全等级:根据安全功能和安全保障要求分为 用户自主保护级  系统审计保护级 安全标记保护级 结构化保护级 访问验证保护级 操作系统作用: 负责计算系统的资源管理、支撑和控制各种应用程序运行,为用户提供计算机系统管理接口 是构成网络信息

可重入锁和不可重入锁概念和区别

可重入锁就是一个类的A、B两个方法,A、B都有获得统一把锁,当A方法调用时,获得锁,在A方法的锁还没有被释放时,调用B方法时,B方法也获得该锁。 这种情景,可以是不同的线程分别调用这个两个方法。也可是同一个线程,A方法中调用B方法,这个线程调用A方法。 不可重入锁就是一个类的A、B两个方法,A、B都有获得统一把锁,当A方法调用时,获得锁,在A方法的锁还没有被释放时,调用B方法时,B方法也获得不

Linux操作系统命令集(一)

最近开了操作系统的课,弄着虚拟机的linux系统命令学学 文件和目录操作命令: ls:列出目录内容 示例:ls -l 以长格式列出目录内容cd:切换目录 示例:cd /home/user 切换到 /home/user 目录mkdir:创建目录 示例:mkdir new_directory 创建名为 new_directory 的目录rmdir:删除空目录touch:创建空文件或更新文件的时间戳

操作系统分页式存储管理

每次输入地址后,计算出页号,若页号越界,则给出错误提示。否则依次调用FIFO和LRU算法,这里值得注意的是,由于我们的FIFO算法先于LRU算法被调用,那么当在处理FIFO算法时,我们暂且不将位视图相应位置做变化,留到处理LRU算法再做处理。 对于FIFO、LRU算法的缺页,我们分两种情况考虑,第一种是模拟栈内还有空间,那么直接将其入栈。第二种是模拟栈内无空间,要发生置换。发生置换时把模拟栈最底

FPGA随记——小说 可综合和不可综合

当然我在网络上找到了些可综合和不可综合的解释 感觉也很有参考价值: https://wenda.so.com/q/1378362174074040 综合就是把你写的rtl代码转换成对应的实际电路。 比如你写代码assign a=b&c; EDA综合工具就会去元件库里拿一个二输入与门出来,然后输入端分别接上b和c,输出端接上a 假如你写了很多这样的语句 assign a=b&c; assig

linux定时监听ssh服务是否启动-------麒麟操作系统永久关闭swap

linux监听ssh服务是否启动 1、监听脚本2、定时任务3、麒麟操作系统,永久关闭swap 1、监听脚本 #在/usr/local/bin目录下新建脚本文件 cd /usr/local/bintouch check_sshd.sh#给可执行权限chmod +x /usr/local/bin/check_sshd.sh 脚本内容如下: #!/bin/bashs