Hot Reload 原理:JIT 增量编译与 State 保留
Hot Reload vs Hot Restart vs Full Restart
| Hot Reload | Hot Restart | Full Restart | |
|---|---|---|---|
| 速度 | < 1s | 2-5s | 5-30s |
| 保留 State | ✅ | ❌ | ❌ |
| 重新执行 main() | ❌ | ✅ | ✅ |
| 使用场景 | UI 调整 | 改了初始状态 | 改了原生代码 |
Hot Reload 的实现原理
Flutter 的 Hot Reload 依赖 Dart VM 的 JIT 模式(Debug 构建)。
步骤一:增量编译
修改 Dart 文件后,Dart 编译器只编译发生变化的库(Library),生成新的内核字节码(Kernel Bytecode)。
修改 lib/src/counter.dart
↓
计算依赖图,找出受影响的库
↓
只重新编译这些库(增量,不是全编译)
↓
生成 .dill 增量字节码
步骤二:注入 Dart VM
增量字节码通过 Observatory 协议(Debug 模式的 VM 服务)发送到正在运行的 Dart VM:
IDE / flutter CLI
↓ (via vm_service protocol)
Dart VM (on device/emulator)
↓
更新变化库的类定义(Class Redefinition)
↓
Dart VM 内的函数表更新为新字节码
这步依赖 Dart VM 的 Hot Reloading API,类似 Java 的 JVM TI(Tool Interface)。
步骤三:触发 Flutter rebuild
注入完成后,Flutter Framework 调用 reassemble(),从根节点开始重建 Widget 树:
// WidgetsBinding.reassembleApplication(简化)
Future<void> reassembleApplication() async {
await buildOwner!.reassemble(renderViewElement!);
}
reassemble 会让所有 dirty 的 Element 重建,所有 Widget 的 build 重新执行。
为什么 State 能保留?
关键在于:Hot Reload 时,Element 树不销毁,只重建 Widget(描述层)。
Hot Reload 前:
StatefulElement (持有 State: {counter = 5})
└── Text Widget
Hot Reload 后(修改了颜色):
同一个 StatefulElement (State: {counter = 5} ← 还在!)
└── 新 Text Widget(颜色更新)
State 对象本身没有被销毁,counter = 5 还在。新的 Widget 配置(如颜色)通过 didUpdateWidget 或 build 更新。
Hot Reload 的限制
不是所有改动都能 Hot Reload,以下情况需要 Hot Restart:
// ❌ 1. 改变 initState 的逻辑
void initState() {
super.initState();
_controller = AnimationController(vsync: this); // 新增这行
// Hot Reload 后 initState 不会重新执行(State 存活)
}
// ❌ 2. 改变枚举或 final 字段的集合
enum MyEnum { a, b } // 新增 c → 需要 Hot Restart
// ❌ 3. 改变 main() 或 app 初始化
void main() {
runApp(MyApp(theme: 'dark')); // 改这里不会生效
}
// ❌ 4. 改变原生代码(AndroidManifest、Info.plist)
// 需要 Full Restart
Flutter 工具链会在 Hot Reload 失败时自动提示,引导用户 Hot Restart。
Debug / Profile / Release 三种模式
| Debug | Profile | Release | |
|---|---|---|---|
| 编译方式 | JIT | AOT | AOT |
| 支持 Hot Reload | ✅ | ❌ | ❌ |
| 支持 DevTools | ✅ | ✅ | ❌ |
| 断言(assert) | ✅ | ❌ | ❌ |
| 代码大小 | 最大 | 中 | 最小 |
| 性能 | 最慢 | 接近 Release | 最快 |
为什么 Profile 模式存在?
Debug 模式有 JIT 开销(解释执行)、断言检查、Observatory overhead,性能与 Release 差距可达 2-5 倍。如果在 Debug 下做性能优化,可能误判。Profile 模式是 AOT 编译(接近真实性能)但保留了性能分析能力(DevTools 连接)。
flutter run --profile # Profile 模式
flutter run --release # Release 模式
使用 Flutter DevTools
DevTools 是 Flutter 官方性能分析工具,可以分析:
- Widget Inspector:查看 Widget 树、RenderObject 尺寸、repaint 边界
- Timeline:每帧的 build/layout/paint 时间,定位 jank
- Memory:内存分配曲线,检测内存泄漏
- CPU Profiler:找出 CPU 热点函数
- Network:监控 HTTP 请求
# 启动 DevTools
flutter pub global activate devtools
flutter pub global run devtools
# 或直接
flutter run --devtools-server-address=localhost:9100
在 Debug/Profile 模式下,IDE(VS Code / Android Studio)通常自动打开 DevTools。