会读才会写
菲利普博士针对社会科学期刊文献的阅读密码表
密码在文中的位置
密码缩写
名称
含义
前言
WTD
他们要做什么(What They Do)
作者(们)声称要在论文 /书中做什么;这一密码提炼出了作者在文本中提出的主要问题。
文献综述
SPL
现有文献综述Summary of Previous Literature)
该句、该段或该页给出了前人研究结果的简要综述。该过程要求大量的提炼工作,要理解复杂的观点并把它们浓缩为几段话或几句话,本领高超的作者甚至能将其浓缩为一句话。
文献综述
CPL
现有文献批评Critique of Previous Literature)
作者评论先行学者著述的学术文献并指出其局限。CPL与POC,GAP以及SPL都有概念联系,因为已有文献在理论、方法论和分析工具方面的不足正是目前研究的必要性之所在。CPL常常会紧随SPL,因为作者首先要提供一些思想作靶子才能进行批评。
文献综述
GAP
空白(Gap)
作者(可能以某种有系统的方式)指出现有文献中缺失的成分。如果GAP和CPL得以恰当操作,那么读者就应该能够在作者明示之前就预测出R ...
29. 持久数据的可靠性
实现可靠的磁盘
持久数据的 “持久”
如果我们的数据 “就地消失”
通讯软件无法使用
支付软件无法使用
没有 “一个” 绝对可靠的存储设备
临时失效
Kernel panic (bug); 断电
部分失效
ECC 纠错失败; fail slow
永久失效
小概率事件:硬盘物理损坏 (大量重复 = 必然发生)
极小概率事件:战争爆发/三体人进攻地球/世界毁灭
RAID: 存储设备的虚拟化
性能和可靠性,我们能不能全都要呢?
Redundant Array of Inexpensive (Independent) Disks (RAID)
把多个 (不可靠的) 磁盘虚拟成一块非常可靠且性能极高的虚拟磁盘
A case for redundant arrays of inexpensive disks (RAID)(SIGMOD’88)
一个 “反向” 的虚拟化
类比:进程/虚存/文件把 “一个设备” 虚拟成多份
RAID: Design Space
RAID (虚拟化) = 虚拟块号到 (磁盘, 块号) 的 “映射”
虚拟磁盘块可 ...
28. 文件系统
文件系统
文件 = struct file_operations
数据文件:hello.c, a.out, …
虚拟的磁盘
vector
设备驱动
null, nuke0, …
虚拟文件
进程的地址空间, …
新需求:怎么管理系统中众多的文件?
find_file_by_name?
管理文件
文件那么多,怎么找到想要的?
信息的局部性:将虚拟磁盘 (文件) 组织成层次结构
思路:信息的局部性
树状层次结构
逻辑相关的数据存放在相近的目录
12345678.└── 学习资料 ├── .学习资料(隐藏) ├── 问题求解1 ├── 问题求解2 ├── 问题求解3 ├── 问题求解4 └── 操作系统
麻烦的是 “非数据” 的文件
UNIX/Linux: Everything is a File
一切都在 “/” 中 (例子:中文语言包, fstab)
Windows 的设计
一个驱动器一棵树:A:, B:, C:, …
其他命名空间:Windows Driver Model, Registr ...
27. 文件和设备驱动
文件和文件描述符
Everything is a File
访问操作系统中的对象
文件:有 “名字” 的对象
字节流 (终端) 或字节序列 (普通文件;包括 /proc/*)
文件描述符
指向操作系统对象的 “指针”
通过指针可以访问 “everything”
对象的访问都需要指针
open, close, read/write (解引用), lseek (指针内赋值/运算), dup (指针间赋值)
应用程序:访问文件
通过系统调用
open, read, write, mmap, …
(当然可以;我们实现过很多这样的程序了)
真的是这样吗?
求证:strace readelf -h /bin/ls
还有更多有趣的例子
LC_ALL=zh_CN.UTF-8 strace readelf -h a.txt
“不是 ELF 文件 - 它开头的 magic 字节错”?
(需要 language-pack-zh-hans)
计算机世界没有魔法!
更多的细节 (1)
文件是 “虚拟磁盘”
把磁盘的一部分映射到地址空间,再自然不过了
...
26. 输入输出设备
计算机系统的最后一块拼图
孤独的 CPU
CPU 只是 “无情的指令执行机器”
取指令、译码、执行
Altair-8800 (1975), with Intel 8080A; 256B 板卡 RAM
(你需要在面板上拨动开关输入执行指令的起始地址)
实现输入/输出
例子:发射核弹
使计算机能感知外部状态 (眼睛、耳朵)、对外实施动作 (手)
GPIO (General Purpose Input/Output)
极简的模型:Memory-mapped I/O 直接读取/写入电平信号
GPIO: 一根可以读写数据的线
12led = LED(2)led.on(); time.sleep(0.03); led.off()
真正的核弹发射器也是类似的原理……
I/O 设备:“计算” 和 “物理世界” 之间的桥梁
I/O 设备 = 一个能与 CPU 交换数据的接口/控制器
就是 “几组约定好功能的线” (寄存器)
通过握手信号从线上读出/写入数据
给寄存器 “赋予” 一个内存地址 (Address Decoder)
CPU 可以直接使用指令 (i ...
25.1-Bit 的存储
状态机和状态
从计算模型到计算机系统
我们需要 “造出” 状态图、纸带……
核心:“纸、铅笔、橡皮”
在物理世界中实现状态
实现 Random Access
磁铁 (1960s)
SRAM: Flip-flop
DRAM: 电容
在物理世界中实现持久化
Persistence: “A firm or obstinate continuance in a course of action in spite of difficulty or opposition.”
我们希望更大、更多的数据能 “留下来” (并且被操作系统有效地管理起来)
持久存储器的抽象
12typedef uint8_t block[4096]; // 4KBblock persist_memory[244140625]; // 1TB
一个巨大的 bit/byte array
允许按 block 读写
磁存储
“持久化” 可能没有想象的那么困难
一个 “能反复改写的状态”
当然,要能寻址 + 用电路改写
电磁感应:物理和数字世界的桥梁
1D 存储设备:把 Bits “卷 ...
15. 进程的地址空间
进程的地址空间
一个很基本 (但也很困难) 的问题
进程的状态机模型
进程状态 = 内存 + 寄存器
到底什么是 “进程的内存”?
以下程序的 (可能) 输出是什么?
printf("%p\n", main);
何种指针访问不会引发segmentation fault?
123char *p = random();*p; // Load*p = 1; // Store
进程的地址空间
RTFM: /proc/[pid]/maps (man 5 proc)
进程地址空间中的每一段
地址 (范围) 和权限 (rwxsp)
对应的文件: offset, dev, inode, pathname
TFM 里有更详细的解释
和 readelf (-l) 里的信息互相验证
更多的提问:我们能 “控制” pmap 的输出吗?
修改堆 (bss) 内存的大小
在栈上分配大数组……
管理进程地址空间
状态机的视角
地址空间 = 带访问权限的内存段
不存在 (不可访问)
不存在 (可读/写/执行)
管理 = 增加/删除/ ...
14. 操作系统上的进程
第一个进程
回顾:进程 = 状态机
编译器:C 状态机 → 汇编状态机的翻译器
特殊的指令/函数:syscall
我们同样可以建模 (模拟) 进程的执行
12345678910def StateMachine(): b = sys_read() if b == 0: sys_write('I got a zero.') else: sys_write('I got a one.')def main(): sys_spawn(StateMachine)
操作系统的启动
Firmware 阶段
CPU Reset 后,Firmware 代码开始执行
加载操作系统
操作系统初始化阶段
操作系统扫描系统中的硬件、初始化数据结构……
加载第一个进程 (状态机)
操作系统执行阶段
状态机在 CPU 上执行
允许执行 syscall 进入操作系统代码
进程的创建
我们能控制这个行为吗?
计算机系统没有魔法
你能想到的事就能实现
人工智能就能帮你实现
我希望用 QE ...
关于对js闭包与防抖的理解
Js内存回收机制
什么是内存回收?
垃圾回收是指自动释放不再使用的内存。程序在运行时会动态分配内存,但并不是所有被分配的内存都会一直被使用。垃圾回收器的任务就是识别那些不再被使用的内存,并将其释放回系统,以便其他进程可以使用。
标记清除(Mark-Sweep)
当函数被调用时,一个新的执行上下文(Execution Context)被创建,变量和参数被创建并加入到这个环境中。这个过程称为变量进入环境。
每个执行上下文都有自己的作用域链,它决定了变量和函数的可见性。作用域链从当前上下文开始,向上遍历至全局上下文。
变量的生命周期从它被创建开始,直到它离开作用域。在变量的生命周期内,它可以被代码访问和使用。
当一个执行上下文被销毁,比如函数执行完毕,这个上下文中的变量就被认为是“离开环境”。此时,这些变量不再被代码所引用。
一旦变量离开环境并且没有任何外部引用指向它们,它们就成为垃圾回收器的候选对象。垃圾回收器会定期检查这些无用的对象,并释放它们占用的内存。
如果一个变量在离开环境后仍然被某些引用所持有,它就不会被回收。例如,如果一个变量被赋予给一个全局变量或者 ...
13. 应对 (并发) Bugs
1 应对死锁
1.1 死锁:一类 “简单” 的并发 Bug
具有明确的 Specification
任何线程在 “基本合理” 的调度下,不能失去进展
甚至有明确的必要条件
Mutual-exclusion - 一个口袋一个球,得到球才能继续
Wait-for - 得到球的人想要更多的球
No-preemption - 不能抢别人的持有的球
Circular-chain - 形成循环等待球的关系
Lock ordering: 避免循环等待
严格按照编号顺序获得所有锁
1.2 死锁:死局
一面是复杂的系统,另一面是不可靠的人
希望
标记 “做一件事” 不被打断
实际
“做一件事” 需要拆解成多个步骤
每个步骤需要上正确 (而且尽可能少) 的锁
LockDoc (EuroSys’19)
“Only 53 percent of the variables with a documented locking rule are actually consistently accessed with the required locks held.” ...