为什么你的程序越跑越快?揭秘计算机底层的“提效”双子星

张开发
2026/5/3 13:37:33 15 分钟阅读
为什么你的程序越跑越快?揭秘计算机底层的“提效”双子星
为什么你的程序越跑越快揭秘计算机底层的“提效”双子星在计算机科学的世界里无论是写 Java 业务代码还是研究操作系统底层我们都会遇到一个极其相似的优化思路“把过去经常使用的代码挑出来做特殊处理以提升效率。”但有趣的是针对同一个核心思想在不同的计算机架构层级它有着完全不同的专业术语和实现路径。今天我们就从Java 虚拟机JVM和操作系统OS底层两个维度彻底扒开计算机“让程序越跑越快”的底层逻辑。一、 JVM 软件层面的魔法热点代码与 JIT 编译如果你使用的是 Java这种将“频繁使用的代码”进行特殊加速的机制造就了两个极其鼎鼎大名的专业术语热点代码Hot Spot Code和JIT 编译Just-In-Time Compilation。这也是目前主流 Java 虚拟机 HotSpot VM 名字的由来。1. 为什么要做特殊处理二八定律计算机科学家早就发现了一个规律一个程序 80% 的运行时间其实都在死磕其中 20% 的代码比如核心的for循环、高频调用的工具方法。如果对所有代码一视同仁地进行顶级编译优化会极大拖慢程序的启动速度并浪费内存但如果能把这 20% 的核心代码揪出来“开小灶”整体性能就会产生质的飞跃。2. 怎么找出这些代码热点探测JVM 内部自带了极其敏锐的“计步器”方法调用计数器记录一个方法被调用的总次数。回边计数器记录一个循环体在内部循环的次数。当这两者的累计次数超过了某个设定好的阈值比如 Server 模式下默认 10000 次JVM 就会猛然惊醒将其标记为“热点代码”。3. JIT 的降维打击一旦被认定为热点代码后台的 JIT 编译器就会立刻介入完成一次“降维打击”执行状态运行方式优缺点普通代码解释执行一行一行将字节码翻译成机器码去跑类似同声传译。启动快但持续运行速度慢。热点代码JIT 编译执行将字节码深度重写并翻译成极度适配当前 CPU 架构的本地机器码 (Native Code)并永久保存在内存的代码缓存 (Code Cache) 里。启动慢需要编译时间但后续执行速度像闪电一样快性能逼近 C。下次程序再运行到这段热点代码时JVM 连“翻译”都省了直接去代码缓存里调取底层机器码执行。这就是为什么 Java 程序往往会“越跑越快”的原因。二、 操作系统硬件层面的铁律局部性原理如果我们把视角往下沉脱离具体的编程语言来到操作系统和 CPU 硬件的层面。你会发现“过去经常使用的代码在未来一段时间很有可能接着使用”这个现象有一个更伟大、更底层的名字局部性原理Principle of Locality。现代计算机的整个存储层级体系几乎都是建立在这个原理之上的。局部性原理包含两大核心法则时间局部性Temporal Locality如果一个数据或程序刚刚被访问过那么在不久的将来它有极高的概率会被再次访问。比如for循环里的计数器变量。空间局部性Spatial Locality如果一个数据刚刚被访问过那么与它物理地址相邻的数据在不久的将来也很可能被访问。比如遍历一个数组读了第 1 个元素大概率马上要读第 2 个。操作系统与 CPU 是如何利用局部性“开挂”的操作系统和硬件对时间局部性可谓是“奉若神明”具体体现在两大核心设计上高速缓存CPU CacheCPU 极其快速而内存RAM相对缓慢。因为有局部性原理CPU 厂商不惜成本在芯片内部集成了 L1、L2、L3 高速缓存。它会把刚用过的指令和数据暂存在离 CPU 运算单元最近的地方。下次再要用时间局部性瞬间就能拿到从而避免了龟速的内存读写。虚拟内存与页面置换Page Replacement当电脑物理内存快被挤爆时操作系统需要把一些暂时不用的程序踢到硬盘的虚拟内存Swap里。操作系统决定“踢谁”的核心依据就是时间局部性如 LRU 算法。它会评估“这几个程序最近一直都在活动未来肯定还要用留在内存那个程序已经半小时没动静了未来大概率不用踢到硬盘去”总结从最底层的CPU 缓存与页面置换局部性原理到上层的JVM 运行机制热点代码与 JIT 编译。虽然它们所处的层级不同解决的具体问题不同但本质上都是计算机科学中一种极具智慧的资源分配哲学将最宝贵的资源极速的存储器、顶级的编译优化倾斜给最高频、最核心的部分。

更多文章