Android进程模型基础

基础回顾

维度 进程 线程
定义 操作系统资源分配的基本单位 CPU调度的基本单位
内存空间 独立内存空间,相互隔离 共享进程的内存空间
通信方式 IPC(Binder、Socket、共享文件等) 共享内存、Handler等
创建开销 大(需分配独立内存空间) 小(共享进程资源)
Android 体现 每个应用默认一个进程,可配置多进程 主线程(UI线程)+ 工作线程

Android进程

Android基于Linux内核,但有自己的进程管理策略

xml 复制代码
// 在AndroidManifest.xml中声明进程
<application
    android:process=":remote">  <!-- 冒号表示私有进程 -->
    
    <!-- 默认情况下,所有组件运行在application指定的进程中 -->
    <activity android:name=".MainActivity" />
    
    <!-- 可以为特定组件指定不同进程 -->
    <service
        android:name=".RemoteService"
        android:process=":background" />
        
    <activity
        android:name=".WebViewActivity"
        android:process=":webview" />
</application>

默认情况下,一个Android应用运行在一个进程中。这个进程的名称通常就是应用的包名。

虽然默认是单进程,但在以下场景中需要考虑多进程:

  • 规避内存限制
xml 复制代码
<!-- 在AndroidManifest中为组件指定独立进程 -->
<application>
    <!-- 主进程,负责UI -->
    <activity android:name=".MainActivity" />
    
    <!-- 独立进程,处理内存密集型任务 -->
    <service
        android:name=".ImageProcessingService"
        android:process=":image_process" />
</application>

每个进程有独立的内存空间。Android为每个进程设置内存上限(比如256MB)。如果应用需要处理大图、视频等,可以放到独立进程,避免主进程OOM。

  • 独立运行的组件
kotlin 复制代码
// 音乐播放器应用:播放服务运行在独立进程
// 这样即使主进程崩溃,音乐还能继续播放
class MusicService : Service() {
    override fun onCreate() {
        super.onCreate()
        Log.d("MusicService", "运行在独立进程,进程名: ${getProcessName()}")
    }
}

使用场景例如:播放器,音乐播放不受UI进程影响;下载器,下载任务独立运行;推送服务,保持长连接,与UI逻辑分离。

  • 隔离不稳定模块
xml 复制代码
<!-- WebView独立进程,避免崩溃影响主应用 -->
<activity
    android:name=".WebViewActivity"
    android:process=":webview" />

WebView、第三方SDK等可能不稳定的模块,放在独立进程可以避免崩溃影响主应用。

  • 提升性能(谨慎使用)
xml 复制代码
<!-- 将频繁GC的后台任务放到独立进程 -->
<service
    android:name=".DataSyncService"
    android:process=":sync" />

如果某个组件频繁创建/销毁对象导致GC,会影响UI流畅度。独立进程后,GC只影响该进程。

多进程优缺点

优点 说明 示例
内存隔离 每个进程独立内存空间,可突破单进程内存限制 图片编辑应用:UI进程 + 图片处理进程
稳定性提升 一个进程崩溃不影响其他进程 WebView崩溃不会导致整个应用退出
安全隔离 敏感操作可在独立进程进行 支付模块运行在独立进程
性能优化 可利用多核CPU并行计算 视频转码应用使用多进程并行处理
缺点 说明 解决方案
通信复杂 进程间不能直接共享内存,需要IPC 使用Binder、Messenger、AIDL等
开销增大 每个进程都有独立的内存、类加载等开销 谨慎创建,避免过多进程
数据同步难 共享数据需要额外机制 使用ContentProvider、文件、SharedPreferences(MODE_MULTI_PROCESS已废弃)
调试困难 多进程调试复杂,需附加到不同进程 使用Android Studio的多进程调试功能

Android进程的创建过程

Zygote:所有应用的"母体"

当系统需要启动一个新的应用时,如果为每个应用都从头初始化整个运行环境(包括加载系统资源、类库等),会非常耗时。Zygote进程就是为了解决这个问题而设计的。

Zygote进程在系统启动时被创建,它已经完成了:

  1. 初始化虚拟机(DVM/ART)
  2. 加载系统资源
  3. 预加载Android框架的类和资源

当需要启动新应用时,Zygote会fork出一个子进程。这个子进程会继承Zygote进程已经加载的系统资源和类,这样新进程就无需重新加载这些,从而大大加快了启动速度。

fork是Unix/Linux系统中创建新进程的系统调用。传统上,fork会复制父进程的整个地址空间给子进程。但是,如果父进程很大,那么复制整个地址空间将会非常耗时,而且子进程可能很快就会通过exec系统调用加载一个新的程序,这样刚才复制的地址空间就被完全替换了,导致复制操作白费了。

为了解决这个问题,现代操作系统(包括Linux)实现了写时复制(Copy-on-Write,简称COW)技术。其核心思想是:当父进程调用fork创建子进程时,内核并不复制整个进程的地址空间,而是让子进程和父进程共享相同的物理内存页。但是,这些内存页会被标记为写时复制。也就是说,当父进程或子进程试图修改某个内存页时,内核才会复制这个页,然后让修改方拥有这个页的私有副本。

这样,fork操作就变得非常轻量,因为只需要复制父进程的页表(一种数据结构,用于将虚拟地址映射到物理地址),而不需要复制实际的物理内存页。子进程几乎可以立即开始运行。

进程优先级:Android如何管理进程生死

Android根据进程的重要性动态调整优先级:

java 复制代码
// ProcessList.java中定义的进程优先级
// 数字越小优先级越高
static final int FOREGROUND_APP_ADJ = 0;      // 前台应用
static final int VISIBLE_APP_ADJ = 100;       // 可见应用
static final int PERCEPTIBLE_APP_ADJ = 200;   // 可感知应用(如播放音乐)
static final int BACKUP_APP_ADJ = 300;        // 备份进程
static final int CACHED_APP_MIN_ADJ = 350;    // 缓存应用(最低)
static final int CACHED_APP_MAX_ADJ = 400;
复制代码
应用启动 → 前台进程(最高优先级)
用户按Home键 → 可见进程(次高优先级)
转到其他应用 → 服务进程(如果有Service)
长时间在后台 → 缓存进程(可能被回收)

Android的进程回收机制主要通过 Low Memory Killer (LMK)OOM Adj评分系统来实现智能管理。

java 复制代码
// 简化版LMK内核代码逻辑(kernel/drivers/staging/android/lowmemorykiller.c)
static int lowmemory_killer(void *arg) {
    while (!kthread_should_stop()) {
        // 1. 检查当前内存压力
        int other_free = global_page_state(NR_FREE_PAGES);
        int other_file = global_page_state(NR_FILE_PAGES);
        
        // 2. 遍历进程,计算"badness"分数
        for_each_process(p) {
            // 跳过不可杀进程(init、kthread等)
            if (p->flags & PF_KTHREAD)
                continue;
            
            // 获取进程的oom_score_adj(用户空间设置)
            int oom_score_adj = p->signal->oom_score_adj;
            if (oom_score_adj == OOM_SCORE_ADJ_MAX)
                continue;
            
            // 3. 计算综合分数
            points = oom_badness(p, NULL, nodemask, totalpages);
            
            // 4. 找到最"坏"的进程
            if (points > selected_points) {
                selected = p;
                selected_points = points;
            }
        }
        
        // 5. 如果内存紧张,杀掉选中的进程
        if (selected) {
            send_sig(SIGKILL, selected, 0);
        }
        
        // 6. 休眠,等待下一次检查
        schedule_timeout_interruptible(poll_interval);
    }
    return 0;
}
相关推荐
GoldenPlayer1 天前
Gradle脚本执行
android
we1less1 天前
[audio] Audio debug
android
Jomurphys1 天前
AndroidStudio - TOML
android
有位神秘人1 天前
Android最新动态权限申请工具
android
lxysbly1 天前
psp模拟器安卓版下载汉化版2026
android
2501_941822751 天前
面向灰度发布与风险隔离的互联网系统演进策略与多语言工程实践分享方法论记录思考汇总稿件
android·java·人工智能
触想工业平板电脑一体机1 天前
【触想智能】工业视觉设备与工控一体机进行配套需要注意的五大事项
android·大数据·运维·电脑·智能电视
Android-Flutter1 天前
android compose PullToRefreshAndLoadMore 下拉刷新 + 上拉加载更多 使用
android·kotlin
似霰1 天前
HIDL Hal 开发笔记4----Passthrough HALs 实例分析
android·framework·hal