<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>速查 on Jasper</title><link>https://jasper-aa64.github.io/zh/ref/</link><description>Recent content in 速查 on Jasper</description><generator>Hugo</generator><language>zh-CN</language><lastBuildDate>Wed, 04 Nov 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://jasper-aa64.github.io/zh/ref/index.xml" rel="self" type="application/rss+xml"/><item><title>CPU 与内存：地图、数字、怎么估算</title><link>https://jasper-aa64.github.io/zh/ref/cpu-memory/</link><pubDate>Thu, 08 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/cpu-memory/</guid><description>&lt;p&gt;这页是随时翻的总图，不是一篇文章。三部分按“在哪 → 多大多快 → 怎么合起来算”排：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://jasper-aa64.github.io/zh/ref/cpu-memory/#map"&gt;存储层次&lt;/a&gt;：硬件地图，一次读写经过哪些框，每个框在哪篇文章里讲过。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jasper-aa64.github.io/zh/ref/cpu-memory/#numbers"&gt;性能参数&lt;/a&gt;：每个框的延迟、带宽、容量，同时能挂几个请求（MLP），以及 CPU 自己想吃多快（带宽需求）。都是帮助理解的量级，不对应哪台机器。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jasper-aa64.github.io/zh/ref/cpu-memory/#estimate"&gt;估算模型&lt;/a&gt;：用一个式子把第 2 部分的数串起来，判断一段代码慢在“搬得多”还是“搬得慢”。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;后面讲到新的硬件层，都补在这一页。往上一层，一条行情经过哪些线程，见&lt;a href="https://jasper-aa64.github.io/zh/ref/trading-architecture/"&gt;交易系统架构&lt;/a&gt;。&lt;/p&gt;</description></item><item><title>C++ 与 Linux：总图</title><link>https://jasper-aa64.github.io/zh/ref/cpp-linux/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/cpp-linux/</guid><description>&lt;p&gt;这页放 C++ 程序在 Linux 上最常翻的总图，和&lt;a href="https://jasper-aa64.github.io/zh/ref/cpu-memory/"&gt;硬件地图&lt;/a&gt;是一对：硬件地图讲一次访存经过哪些硬件，这页讲在那之前，操作系统替程序做了什么。三张图：&lt;a href="https://jasper-aa64.github.io/zh/ref/cpp-linux/#map"&gt;进程地图&lt;/a&gt;讲一个进程的内存长什么样，&lt;a href="https://jasper-aa64.github.io/zh/ref/cpp-linux/#io"&gt;IO 地图&lt;/a&gt;讲数据怎么进出这个进程，&lt;a href="https://jasper-aa64.github.io/zh/ref/cpp-linux/#build"&gt;从源码到进程&lt;/a&gt;讲一个可执行文件是怎么编出来、又怎么变成进程的。细分的知识点（epoll、fork、动态链接……）写成单页，和这页一起放在 &lt;a href="https://jasper-aa64.github.io/zh/interview/#cpplinux"&gt;IV 栏的 C++ 与 Linux 这一组&lt;/a&gt;，这页只放总图和最常翻的表。&lt;/p&gt;
&lt;h2 id="map"&gt;&lt;span class="h-num"&gt;1.&lt;/span&gt; 进程地图：一个进程的虚拟地址空间&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://jasper-aa64.github.io/maps/process-map.zh.html" target="_blank" rel="noopener"&gt;&lt;img src="https://jasper-aa64.github.io/images/ref/process-map.zh.svg" alt="进程地图：左边是 x86-64 上一个进程的虚拟地址空间，从高到低依次是内核空间、非规范地址空洞、主线程的栈、vDSO、mmap 区（共享库、大块 malloc、其他线程的栈和 TLS、文件映射和共享内存）、没映射的空地、堆、.bss、.data、.rodata、.text 和最低 64 KiB 的不映射区；右边是 C++ 变量各放在哪、线程共享什么、页表和缺页怎么把虚拟地址落到物理内存、在自己机器上怎么看、出了错落在哪一段。" loading="lazy" decoding="async"&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>交易系统架构：地图、时间、怎么切</title><link>https://jasper-aa64.github.io/zh/ref/trading-architecture/</link><pubDate>Tue, 20 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/trading-architecture/</guid><description>&lt;p&gt;这页是随时翻的架构总图，和&lt;a href="https://jasper-aa64.github.io/zh/ref/cpu-memory/"&gt;硬件地图&lt;/a&gt;是一对：那页讲一次访存经过哪些硬件，这页讲一条行情经过哪些线程。三部分按“在哪 → 多快 → 怎么切”排：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://jasper-aa64.github.io/zh/ref/trading-architecture/#map"&gt;架构地图&lt;/a&gt;：一条行情变成一笔成交，经过哪些框，每个框在哪篇文章里讲过。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jasper-aa64.github.io/zh/ref/trading-architecture/#numbers"&gt;时间&lt;/a&gt;：每一段大概多久，用来判断该抠哪一段。都是量级，不对应哪套系统。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jasper-aa64.github.io/zh/ref/trading-architecture/#rules"&gt;怎么切&lt;/a&gt;：工业级系统怎么分线程、在哪里放队列、哪里必须汇合。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;后面讲到新的组件，都补在这一页。&lt;/p&gt;
&lt;h2 id="map"&gt;&lt;span class="h-num"&gt;1.&lt;/span&gt; 架构地图：一条行情经过哪些框&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://jasper-aa64.github.io/maps/arch-map.zh.html" target="_blank" rel="noopener"&gt;&lt;img src="https://jasper-aa64.github.io/images/ref/arch-map.zh.svg" alt="交易系统架构地图：交易所的行情经网卡进行情接入线程，先写一份进广播环给落盘和监控，再按股票分到各分片线程算盘口和因子，汇合后进决策线程的策略、风控、订单管理和下单网关，经券商柜台到交易所；回报沿红线回到订单管理和账户状态，再回到策略。最下面一排是旁路：离线回放、落盘、监控、日志、交易员指令和客户端推送。" loading="lazy" decoding="async"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;绿框是热线程，各绑一个隔离核；蓝框是线程之间交接数据的结构；黄框是汇合点；最下面一排虚线框是旁路。黑线是行情到报单，红线是回报回来，灰色虚线是旁路。点图打开可交互的版本：点一个框看它做什么、为什么这样设计；选一条路径，一步一步看怎么走。&lt;/p&gt;</description></item><item><title>perf</title><link/><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid/><description>&lt;p&gt;速查列表里的一条入口，不是单独的页面：卡片链到 &lt;code&gt;target&lt;/code&gt; 指的那篇文章，标题、简介和日期都从那篇读，文章本身是唯一的一份。&lt;/p&gt;</description></item><item><title>性能瓶颈：信号、原因、修法</title><link>https://jasper-aa64.github.io/zh/ref/bottlenecks/</link><pubDate>Thu, 22 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/bottlenecks/</guid><description>&lt;!-- 卡片的源文件在 content/bottlenecks/：中文 &lt;id&gt;.zh.md，英文 &lt;id&gt;.md，文件名就是 id，也是下面的锚点。第 1、2 节由短代码 bottleneck-lookup、bottleneck-cards 从这些文件自动汇总；文章末尾用短代码 bottleneck 按 id 嵌入同一份卡片。加一种瓶颈只需新增这两个文件。 --&gt;
&lt;p&gt;用 &lt;a href="https://jasper-aa64.github.io/zh/posts/low-latency-perf-profiling/"&gt;perf&lt;/a&gt; 找到热点以后，下一步是认出它是哪种瓶颈、照什么办法改。这一页把常见的瓶颈各写成一张卡片：信号是在 perf 里或源码里看到什么，原因是为什么慢，修法是怎么改，验证是怎么确认改对了，原理链到站内讲这个机制的文章。&lt;/p&gt;</description></item><item><title>左值、右值和移动语义：std::move、完美转发</title><link>https://jasper-aa64.github.io/zh/ref/move-semantics/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/move-semantics/</guid><description>移动就是把源对象的指针拿过来、把源对象留成空的，只拷几个字节。std::move 只是一次类型转换，真正挑中移动构造的是重载决议；有名字的右值引用本身是左值，所以模板里要用 std::forward 把参数按原来的类别转出去。</description></item><item><title>构造、拷贝、析构和 RAII：对象的一生和异常安全</title><link>https://jasper-aa64.github.io/zh/ref/special-members-raii/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/special-members-raii/</guid><description>类自己管资源，就要自己写析构、拷贝和移动；能交给 std::string、vector、unique_ptr 管的，一个都不用写。RAII 让资源跟着对象走：不管是正常 return 还是异常，离开作用域都会调析构函数，这是 C++ 里做清理的标准办法。</description></item><item><title>虚函数：vptr、vtable 和动态多态</title><link>https://jasper-aa64.github.io/zh/ref/virtual-functions/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/virtual-functions/</guid><description>虚调用 = 读对象开头的 vptr → 读这个类 vtable 里那一格 → 按读到的地址跳。最贵的通常不是这一跳，而是编译器没法内联；类型在编译期就能定时，可以改用静态多态。要复用一个类的实现，放成成员，不要继承它。</description></item><item><title>对象布局：对齐、填充、vptr 和 vtable</title><link>https://jasper-aa64.github.io/zh/ref/object-layout/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/object-layout/</guid><description>对象的大小 = 成员 + 为对齐补的填充，按从大到小排成员填充最少；空类做基类可以不占空间。有虚函数时对象只多一个 8 字节的 vptr，函数再多也只是表变长；vtable 每个类一张，放在重定位后变只读的 .data.rel.ro。多继承时第二个基类子对象有自己的 vptr，转换指针要加偏移，经它调用的虚函数要先过一个调整 this 的 thunk。</description></item><item><title>const、constexpr、consteval、constinit：哪个保证编译期算</title><link>https://jasper-aa64.github.io/zh/ref/const-constexpr/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/const-constexpr/</guid><description>const 管的是能不能改，不管什么时候算；要编译期算出来，变量用 constexpr，函数用 consteval；静态变量怕初始化顺序问题，用 constinit。</description></item><item><title>lambda 和 std::function：闭包对象、捕获和类型擦除</title><link>https://jasper-aa64.github.io/zh/ref/lambda-function/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/lambda-function/</guid><description>lambda 就是一个带 operator() 的类，按模板传进去和手写函数一样快；std::function 换来的是“任何可调用的东西都能放进同一个类型”，付出的是可能的堆分配和一次不能内联的间接调用。捕获引用时，被捕获的变量得比 lambda 活得久。</description></item><item><title>四种 cast：static_cast、dynamic_cast、const_cast、reinterpret_cast</title><link>https://jasper-aa64.github.io/zh/ref/cpp-casts/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/cpp-casts/</guid><description>static_cast 是编译期的、会调整指针但不检查；dynamic_cast 是运行时的、会检查但要查表；const_cast 只动 const；reinterpret_cast 只换解释方式，拿来读写别的类型的对象多半是未定义行为，看字节用 std::bit_cast。C 风格转换会替你挑一种，挑的那种不一定是你以为的。</description></item><item><title>new 一次走到哪：operator new、malloc、brk/mmap 和缺页</title><link>https://jasper-aa64.github.io/zh/ref/new-malloc-page-fault/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/new-malloc-page-fault/</guid><description>new 拿到的是地址，不是内存。malloc 大多数时候在自己手里的空闲块里就找到了，进内核的 brk、mmap 也只是登记一段地址；物理页要等第一次写才由缺页分配，每页一次，每次约 0.5–2 µs。所以第一遍写一块新内存比第二遍慢，delete 之后 RSS 不降也不等于泄漏。</description></item><item><title>函数调用栈帧：返回地址、寄存器传参和栈溢出</title><link>https://jasper-aa64.github.io/zh/ref/stack-frame/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/stack-frame/</guid><description>栈帧就是一次调用在栈上占的那一块：call 把返回地址压进去，函数开头保存旧的 rbp、把 rsp 往下挪出局部变量的位置，ret 再把返回地址弹回 rip。参数前 6 个走寄存器，大对象由调用者在自己的帧里留好位置、把地址悄悄传进去，RVO 就是被调用者直接在那里构造。栈上的三种常见错误都能在这张图上找到位置：越过栈底的保护页、指向已经被下一帧覆盖的格子、写过头盖掉返回地址。</description></item><item><title>智能指针：unique_ptr、shared_ptr 和 weak_ptr</title><link>https://jasper-aa64.github.io/zh/ref/smart-pointers/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/smart-pointers/</guid><description>默认用 unique_ptr：所有权只有一份，大小和裸指针一样。对象的寿命真要由几方共同决定时才用 shared_ptr，复制要付一次原子加，线程安全的只有计数；指回去的边、观察者、缓存用 weak_ptr，用之前 lock() 一下。</description></item><item><title>线程同步：互斥锁、条件变量、信号量、读写锁和死锁</title><link>https://jasper-aa64.github.io/zh/ref/thread-sync/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/thread-sync/</guid><description>共享数据要么同一时刻只让一个线程碰（互斥锁），要么让等的线程睡到条件成立（条件变量、信号量）；条件检查和睡下必须在同一把锁里完成，否则唤醒会丢。死锁的根源是环形等待，固定顺序或一次拿齐就拆掉了环。</description></item><item><title>用户态和内核态：什么时候进内核，什么时候回来</title><link>https://jasper-aa64.github.io/zh/ref/user-kernel-mode/</link><pubDate>Wed, 04 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/user-kernel-mode/</guid><description>进内核不是换线程，是同一个线程换到 Ring 0 跑内核代码。三种入口里，系统调用和异常由自己的代码引起，改代码能避开；中断要靠配置挪走。一次空的系统调用约 50–150 ns，拖成长尾的是在内核里睡下，或者回来前被调度走。</description></item><item><title>线程池和 future：std::thread、promise、packaged_task、async</title><link>https://jasper-aa64.github.io/zh/ref/thread-pool-future/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/thread-pool-future/</guid><description>future 拿结果靠的是一块共享状态：promise 写、future 读，各一次；packaged_task 和 async 都是在它外面再包一层。线程池就是一个加锁的任务队列加几个一直在取任务的线程，难点在停止：标志要在锁里改，队列要先做完。</description></item><item><title>进程和线程：fork、写时复制、共享与独占、进程状态</title><link>https://jasper-aa64.github.io/zh/ref/process-thread-fork/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/process-thread-fork/</guid><description>进程和线程在内核里是同一种东西，差别是共享多少：线程共用一份地址空间和一张 fd 表，只独占栈、寄存器和 TLS。fork 只复制页表，物理页等到有人写才复制，所以 fork 加 exec 很便宜；fork 之后两边的 fd 指着同一个打开的文件。进程退出后留下一条记录等父进程 wait，没人收就是僵尸；父进程先走，子进程交给 init 或最近的 subreaper 收。</description></item><item><title>进程间通信：管道、共享内存、信号和 socket</title><link>https://jasper-aa64.github.io/zh/ref/ipc/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/ipc/</guid><description>进程间通信的方式看起来很多，按数据走不走内核只分两类。管道和 socket 让内核转交：写的一方拷进内核缓冲区，读的一方拷出来，内核顺便管了排队、满了阻塞、空了等待、对端关闭。共享内存让两个页表指向同一批物理页：建好以后读写就是普通访存，0 次拷贝、0 次系统调用，但没人告诉对方“数据到了”，也没人拦着两边同时写。信号和 eventfd 只传通知，不传数据。</description></item><item><title>文件 IO：fd、打开的文件和 inode</title><link>https://jasper-aa64.github.io/zh/ref/file-io/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/file-io/</guid><description>fd → 打开的文件（偏移、O_APPEND、O_NONBLOCK）→ inode（大小、权限、链接数、数据块）。dup 和 fork 复制的是指向第二层的指针，所以共用偏移；重定向就是 open 加 dup2。数据到磁盘前要过两层缓冲：FILE* 的用户态缓冲靠 fflush 推进内核，页缓存靠 fsync 推上磁盘。</description></item><item><title>epoll：红黑树、就绪链表和回调</title><link>https://jasper-aa64.github.io/zh/ref/epoll-internals/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/epoll-internals/</guid><description>epoll 在内核里有三样东西：红黑树记着关注哪些 fd，只给 epoll_ctl 用；就绪链表记着哪些 fd 现在有事，回调往里挂，epoll_wait 从里取；等待队列记着谁睡在 epoll_wait 里。事件来的时候不查树，靠的是登记时挂在 socket 上的那个指针。所以连接再多，每一圈事件循环的开销只看真正有事件的那几个；但每一次 epoll_wait、每一次 recv 仍然是一次系统调用。</description></item><item><title>TCP：三次握手、四次挥手和 TIME_WAIT</title><link>https://jasper-aa64.github.io/zh/ref/tcp-states/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/tcp-states/</guid><description>握手是两个方向各对一次序列号，中间两步合成了 SYN+ACK；第三个报文让发起方能拒绝迟到的旧 SYN。accept 不参与握手，只从全连接队列里取走一条建好的连接。挥手时 ACK 由内核当场回，FIN 要等程序 close，所以通常是四个报文。CLOSE_WAIT 没有超时，成堆出现就是程序漏了 close；TIME_WAIT 是先关的一方替连接收尾，在 Linux 上固定 60 s，太多时靠复用连接解决。</description></item><item><title>TCP 怎么做到可靠：确认重传、流量控制、拥塞控制</title><link>https://jasper-aa64.github.io/zh/ref/tcp-reliability/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/tcp-reliability/</guid><description>可靠靠编号加确认：没确认的就重传，连着 3 个重复确认不等超时就重传。能发多少看两个窗口：接收方的 rwnd 防止把对方的缓冲区塞爆，发送方自己的 cwnd 防止把网络塞爆，发送窗口取两者的较小值。TCP 是字节流，没有消息边界，消息要自己用长度前缀或分隔符切出来。</description></item><item><title>socket 编程：服务端和客户端各调哪几个函数</title><link>https://jasper-aa64.github.io/zh/ref/socket-programming/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/socket-programming/</guid><description>服务端的 socket 先 bind 地址、再 listen 变成监听 socket，握手由内核完成，accept 只是从队列里取走一条建好的连接，换来一个新 fd；客户端 connect 时内核替它挑本地端口。TCP 只保证字节按序到达，不保证一次 read 拿到一条完整消息，所以读写都要循环、消息边界要协议自己定。并发从每连接一个进程或线程，走到一个线程用 epoll 等很多个非阻塞 socket，回调里绝不能阻塞。</description></item><item><title>HTTP 和 HTTPS：一次请求从输入网址到拿到页面</title><link>https://jasper-aa64.github.io/zh/ref/http-basics/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/http-basics/</guid><description>一个新的 HTTPS 请求，要等 DNS、TCP 握手、TLS 握手各花掉时间，才轮到真正的请求，复用连接就是为了省掉前面几段。HTTP 消息在 TCP 字节流上靠空行和 Content-Length（或分块）划出边界；HTTP/2 用流解决了应用层的排队，却躲不开 TCP 的按序交付，HTTP/3 才把流做进 QUIC。TLS 用非对称密码学商量出密钥、证明服务器身份，数据本身用对称加密，因为快几个数量级。</description></item><item><title>STL 容器的底层：vector、deque、list、map、unordered_map</title><link>https://jasper-aa64.github.io/zh/ref/stl-containers/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/stl-containers/</guid><description>容器的复杂度和迭代器失效规则都不用背，从它在内存里的样子就能推出来：连续内存的 vector 搬家时一切都失效，节点式的 list、map 只有被删的那个失效，unordered_map rehash 时迭代器失效、引用不失效。</description></item><item><title>LRU 缓存：哈希表加双向链表</title><link>https://jasper-aa64.github.io/zh/ref/lru-cache/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/lru-cache/</guid><description>LRU 要两样东西：按 key 一步找到，按使用先后排好队。哈希表给前一样，双向链表给后一样，哈希表的值存链表节点的位置把两者接上。命中时用 splice 把节点挪到头部，节点不动、位置不变，哈希表也不用改。</description></item><item><title>跳表、红黑树、B+ 树：三种有序结构各用在哪</title><link>https://jasper-aa64.github.io/zh/ref/skiplist-rbtree-bplustree/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/zh/ref/skiplist-rbtree-bplustree/</guid><description>三者都是 O(log n) 的有序结构，差别在每一步的代价落在哪：红黑树和跳表在内存里，一步是一次指针跳转，比的是实现难度和改动范围；B+ 树在磁盘上，一步是一次读页，所以要把树做得又宽又矮。</description></item></channel></rss>