天天看点

多进程的利弊

简介

进程(process):每个APP在启动前必须创建一个进程,该进程是由Zygote进程(孵化器) fork出来的,进程具有独立的资源空间,用于承载APP上运行的各种Activity,Service等组件。一般情况下,一个APP内只有一个进程,除非在AndroidManifest.xml中配置Android:processs属性,四大组件(Activity,Service,BroastReceiver,ContentProvide)都可以 单独指定进程;或者通过native代码fork进程。

多进程

多进程的好处

1:增加内存分配,降低OOM概率;Android中的内存分配,是以进程分配的,单一进程的内存有限,当APP中包含各种不同业务,展示大量图片,加载大图片,WebView等情况下,会造成OOM,可以考虑多进程增加内存,减轻主进程压力;

2:单一进程崩溃不影响整体应用的使用,提高用户体验;

3:协作开发,模块解耦,组件化,模块化开发;

4:主进程退出,子进程依然可以正常运行(如推送服务,子进程内定义广播接收者)

多进程的弊端

每个进程都有独立的内存分配,不同的进程相互独立,无法共享数据;

1:Application初始化多次

2:静态成员变量,单例模式失效(不是同一块内存,会产生不同的副本)

3:文件共享问题,线程同步机制失效;

4:断点调试

如何解决

解决方法

1:针对Application的多次重建:

多进程的利弊

可以在Application的onCreate方法中判断当前运行的进程做不同的处理解决资源重复初始化的问题

public class MyApplication extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    //获取进程Id
    int pid = android.os.Process.myPid();
    Log.e("m_tag", "MyApplication onCreate pid is " + pid); //根据进程id获取进程名称
    String processName = getProcessName(this,pid);
    if ("test.demo.com.aidltest".equals(processName)) {
      Log.e(TAG, "我是主进程");
      //处理该进程的业务
    } else if ("test.demo.com.aidltest:remote".equals(processName)) {
      Log.e(TAG, "我是子进程");
      //处理该进程的业务
    } 
  }

  public String getProcessName(Context cxt, int pid) {
    ActivityManager am = (ActivityManager)cxt.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
    if (runningApps == null) {
      return null;
    }
    for (RunningAppProcessInfo procInfo : runningApps) {
      if (procInfo.pid == pid) {
      return procInfo.processName;
    }
  }
  return null;
  }
}
           

2:单例和静态成员变量失效,不同的进程中获取的单例实例不是同一块内存,静态变量也是不同的副本:

使用Intent或者aidl等进程通讯方式传递内容,不能用静态或单例模式。

3:针对文件共享问题:

多进程情况下会出现两个进程在同一时刻访问同一个数据库文件的情况。这就可能造成资源的竞争访问,导致诸如数据库损坏、数据丢失等。在多线程的情况下我们有锁机制控制资源的共享,但是在多进程中比较难,虽然有文件锁、排队等机制,但是在Android里很难实现;SharePreferences可靠性下降,不支持多个进程同时写,可能数据丢失;解决办法就是多进程的时候不并发访问同一个文件,比如子进程涉及到操作数据库,就可以考虑调用主进程进行数据库的操作;SharePreferences只用主进程存取,通过IPC机制传递数据。

4:针对断点调试问题:

调试就是跟踪程序运行过程中的堆栈信息,由于每个进程都有自己独立的内存空间和各自的堆栈,无法实现在不同的进程间调试。因此要改为同一进程:调试时去掉AndroidManifest.xml中android:process标签,这样保证调试状态下是在同一进程中,堆栈信息是连贯的。待调试完成后,再将标签复原。

解决进程间通信可以IPC机制,相互传递数据,单一进程用数据库,SharePreferences等存取数据;

如有问题,请多指教!