Appearance
进程与线程管理
1. 进程模型
1.1 鸿蒙进程模型概述
进程模型层次:
┌─────────────────────────────────────┐
│ Application(应用) │
│ ├── UIAbility(UI 界面入口) │
│ └── ExtensionAbility(扩展组件) │
├─────────────────────────────────────┤
│ Process(进程) │
│ ├── 应用进程(Application Process) │
│ ├── 系统进程(System Process) │
│ └── 服务进程(Service Process) │
├─────────────────────────────────────┤
│ Thread(线程) │
│ ├── UI 线程(主线程) │
│ ├── Worker 线程(工作线程) │
│ └── System Thread(系统线程) │
└─────────────────────────────────────┘1.2 进程分类
| 类型 | 说明 | 优先级 | 生命周期 |
|---|---|---|---|
| 前台进程 | 有正在交互的 UI | FOREGROUND(最高) | 直到用户退出 |
| 可见进程 | 有可见但非交互的 UI | VISIBLE | 直到不可见 |
| 服务进程 | 有后台服务运行 | SERVICE | 直到服务停止 |
| 后台进程 | Activity 在后台(onBackground) | BACKGROUND | 内存紧张时被杀 |
| 空进程 | 无活跃组件 | EMPTY(最低) | 立即可被杀 |
1.3 与 Android 进程模型对比
| 维度 | Android | 鸿蒙 |
|---|---|---|
| 进程入口 | Activity/Service | UIAbility/ExtensionAbility |
| 进程隔离 | UID 隔离 | TokenID + 沙箱隔离 |
| 进程间通信 | Binder | IPC (Port + MessageQueue) |
| 进程优先级 | 5 级(foreground→empty) | 6 级(含 process-group) |
| OOM Killer | Adj 值排序 | 重要性等级排序 |
| 多进程 | 声明式(android:process) | 声明式(process 属性) |
| 启动方式 | fork + Zygote 连接 | fork + Zygote Socket |
2. 进程生命周期
2.1 UIAbility 进程状态转换
┌──────────────┐
│ 已创建 │
│ onCreate │
└──────┬───────┘
│
┌──────▼───────┐ 用户切出
│ 前台运行 │◄──────────┐
│ onForeground │ │
└──────┬───────┘ │
│ │
┌──────▼───────┐ 重新切入
│ 后台暂停 │──────────►│
│ onBackground │ │
└──────┬───────┘ │
│ │
┌──────▼───────┐ 长时间/低内存
│ 终止 │──────────►│
│ onDestroy │ │
└──────────────┘ │2.2 进程保活策略
arkts
// 鸿蒙进程保活机制
import { common } from '@kit.AbilityKit';
// 1. 提升进程优先级:启动前台服务
async function keepProcessAlive() {
const foregroundService = {
foregroundServiceType: 'common',
notificationId: 1001,
content: {
title: '服务运行中',
text: '后台任务执行中',
}
};
await this.context.startForegroundService(foregroundService);
}
// 2. 使用 WorkScheduler 执行后台任务
import { workScheduler } from '@kit.BusinessKit';
await workScheduler.scheduleAbility({
bundleName: 'com.example.myapp',
abilityName: 'BackgroundWorkAbility',
type: workScheduler.WorkType.WORK_TYPE_PERIODIC,
interval: 3600000, // 1 小时
periodic: true,
});2.3 进程回收策略
回收优先级(从高到低):
1. 空进程 (EMPTY) — 可立即回收
2. 后台进程 (BACKGROUND) — 可回收
3. 服务进程 (SERVICE) — 谨慎回收,通知用户
4. 可见进程 (VISIBLE) — 仅在内存极紧张时
5. 前台进程 (FOREGROUND) — 几乎不回收
OOM 评分公式(简化):
score = base_score + process_type_penalty + cpu_time_penalty3. 线程模型(Actor 模型)
3.1 ArkTS 线程模型
鸿蒙采用 Actor 模型作为核心并发模型:
Actor 特性:
├── 线程隔离:每个 Actor 运行在独立线程上
├── 消息传递:通过消息队列通信,无共享内存
├── 无锁设计:不需要同步原语,避免死锁
├── 轻量级:线程创建开销低(~100μs)
└── 结构化:线程池统一管理3.2 TaskPool(推荐方案)
arkts
// TaskPool 是系统管理的线程池,适合短时任务
import { taskpool } from '@kit.ArkTaskPool';
// 定义任务函数
@worker
function fetchData(url: string): string {
// 在工作线程中执行网络请求
return http.get(url).sync();
}
// 使用 TaskPool
async function loadData() {
// 1. 注册任务
await taskpool.register(fetchData);
// 2. 提交任务
const promise = taskpool.run(fetchData, ['https://api.example.com/data']);
// 3. 获取结果
const result = await promise;
console.log('Data: ' + result);
}
// TaskPool vs Worker 对比:
// TaskPool: 系统管理,自动调度,适合短时 (< 5s) 任务
// Worker: 手动管理,适合长时 (> 5s) 或常驻任务3.3 Worker(长时任务)
arkts
// Worker 适合长时间运行或常驻任务
// 需要手动创建和管理
@worker
class MyWorker {
private running: boolean = false;
start() {
this.running = true;
while (this.running) {
// 执行常驻任务
this.processData();
}
}
stop() {
this.running = false;
}
private processData() {
// 处理数据
}
}
// 创建和销毁 Worker
const worker = new MyWorker();
worker.start();
// ... 完成时
worker.stop();3.4 线程池使用
arkts
import { thread } from '@kit.ArkThread';
// 1. 获取系统线程池
const executor = thread.createExecutor();
// 2. 提交任务到线程池
const future = executor.submit(() => {
// 异步任务
return heavyComputation();
});
// 3. 获取结果
const result = future.get(); // 阻塞等待
// 4. 线程池资源释放
executor.shutdown();3.5 主线程与工作线程
arkts
// ⚠️ 关键规则:UI 操作只能在主线程进行
@Entry
@Component
struct WorkerDemo {
@State message: string = '加载中...';
@State isLoading: boolean = false;
aboutToAppear() {
// 在主线程:可以直接更新 @State
this.message = '开始加载';
// 提交到工作线程
taskpool.run(() => {
// 工作线程:不能更新 @State
const data = this.fetchFromServer();
// ✅ 正确:通过 callback 回到主线程更新
this.$emit('dataLoaded', data);
}).catch((err: Error) => {
// ✅ 正确:主线程中处理错误
this.message = '加载失败: ' + err.message;
});
}
fetchFromServer(): string {
// 模拟网络请求
return 'Server Data';
}
}4. 线程调度
4.1 调度策略
| 策略 | 说明 | 适用场景 |
|---|---|---|
| SCHED_OTHER | CFS 公平调度(默认) | 普通应用任务 |
| SCHED_FIFO | 实时先入先出 | 音视频处理 |
| SCHED_RR | 实时轮转调度 | 实时通信任务 |
| SCHED_DEADLINE | 截止期调度 | 严格实时任务 |
4.2 线程优先级
优先级范围:0(最低)~ 127(最高)
────────────────────────────────────
SCHED_DEADLINE: 0-99(高优先)
SCHED_FIFO/RR: 0-99(高优先)
SCHED_OTHER: -20~19(相对 Linux nice)
────────────────────────────────────
系统限制:用户线程最高优先级 ≤ 63(防止饿死内核)arkts
import { thread } from '@kit.ArkThread';
// 创建高优先级线程
const highPriorityThread = await thread.startThread({
name: 'high-priority-worker',
prio: thread.ThreadPriority.HIGH, // 优先级
onExit: (code) => console.log('Done'),
});5. OOM Killer
5.1 OOM 机制
OOM Killer 触发条件:
├── 可用内存 < 阈值(可配置)
├── 连续分配失败(kmalloc 返回 NULL)
└── 内存压力达到 OOM_SCORE 阈值
OOM 评分因素:
├── 进程重要性(前台 > 后台)
├── 进程驻留时间
├── 进程的 RSS/VSZ 大小
├── 进程是否有子进程
└── 手动设定的 oom_adj 值5.2 内存回收流程
1. 内存分配失败
2. 触发内存回收(kswapd / khugepaged)
3. 扫描 LRU 链表,释放可回收页面
4. 如果仍不足 → OOM Killer 介入
5. 按重要性排序,杀死最低优先级进程
6. 释放内存 → 原请求分配成功5.3 OOM 防护策略
arkts
// 1. 主动释放不需要的资源
@Entry
@Component
struct MemoryAwareComponent {
@State imageData: string = '';
// 页面隐藏时释放大图内存
onWillDisappear() {
this.imageData = ''; // 释放图片数据
}
// 页面显示时按需加载
onWillAppear() {
// 仅在需要时加载
}
}
// 2. 使用 Weakref 管理长生命周期引用
// 3. 图片使用 decodePixel 下采样
// 4. 避免在 @State 中存放大对象
// 5. 及时关闭文件句柄和数据库连接5.4 内存泄漏检测
检测手段:
├── DevEco Profiler Memory 面板
├── Heap Snapshot 对比
├── @State 大对象检查
├── 闭包中意外引用(闭包陷阱)
└── 监听器未注销(addEventListener)
常见泄漏场景:
├── @State 存储大数组/对象
├── 定时器未清理(clearTimeout)
├── 网络请求未 abort
├── 自定义事件监听未 removeListener
└── 闭包中持有 UIComponent 引用6. 🎯 面试高频考点
Q1: 鸿蒙的 Actor 线程模型与 Android 线程模型有什么区别?
答要点:
- 鸿蒙 Actor 模型:线程隔离 + 消息传递,无共享内存,天然避免竞态条件
- Android 线程模型:共享内存 + 同步原语(mutex/semaphore),需要手动处理同步
- 鸿蒙 TaskPool 由系统管理,Android Handler/Executor 需要手动管理
- 鸿蒙禁止跨线程操作 UI,Android 通过 Handler 回调到主线程
Q2: TaskPool 和 Worker 怎么选?
答要点:
- TaskPool:系统管理线程池,适合短时任务(< 5s),无需手动管理
- Worker:手动创建管理,适合长时任务(> 5s),可常驻运行
- TaskPool 有任务超时机制(默认 60s),Worker 无超时限制
- TaskPool 自动回收线程,Worker 需要手动 shutdown
- 大量短时任务优先用 TaskPool(减少线程创建开销)
Q3: 鸿蒙如何防止 OOM?
答要点:
- 架构层面:分层 OOM Killer,按重要性排序回收
- 开发层面:避免 @State 存储大对象,及时释放资源
- 图片处理:使用 decodePixel 下采样,按需加载
- 懒加载:LazyForEach 按需加载列表
- 缓存策略:实现 LruCache,设置大小上限
- 监控:使用 Profiler 定期检测内存泄漏
💡 面试提示:Actor 模型是鸿蒙并发的核心,对比 Android 的 Handler 模型强调无锁、线程隔离的优势。TaskPool vs Worker 是高频对比题。