转自:https://blog.csdn.net/xxm282828/article/details/49095839

Android启动过程中针对类和资源部分预加载耗时比较久,这个部分需要优化,主要涉及的文件:

./base/core/java/com/android/internal/os/ZygoteInit.java

主要采取三个措施:

1. 修改ZygoteInit.java 中预加载资源函数preload() ,  preloadClasses(); 与 preloadResources(); 并行加载。2. 修改读取配置信息过程中GC频率。3. 提升进程优先级

1、资源和类并行加载:

    static void preload() {        //        Thread  preloadRsThread = new Thread(new Runnable(){             @Override            public void run() {                // TODO Auto-generated method stub            //将该资源加载放在子线程中  。加载资源文件要比加载classes文件要快,因此这里不提升子线程优先级。              preloadResources();            }         }) ;         preloadRsThread.start() ;        preloadClasses();        //wait preloadRes complete.        try {            preloadRsThread.join() ;        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }               //暴露什么问题。        preloadOpenGL();   }

2、减少GC的频繁调度:

    /**    * Performs Zygote process initialization. Loads and initializes     * commonly used classes.     *     * Most classes only cause a few hundred bytes to be allocated, but     * a few will allocate a dozen Kbytes (in one case, 500+K).     */    private static void preloadClasses() {        final VMRuntime runtime = VMRuntime.getRuntime();         InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(                PRELOADED_CLASSES);        if (is == null) {            Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");        } else {            Log.i(TAG, "Preloading classes...");            long startTime = SystemClock.uptimeMillis();             // Drop root perms while running static initializers.            setEffectiveGroup(UNPRIVILEGED_GID);            setEffectiveUser(UNPRIVILEGED_UID);             // Alter the target heap utilization.  With explicit GCs this            // is not likely to have any effect.            float defaultUtilization = runtime.getTargetHeapUtilization();            runtime.setTargetHeapUtilization(0.8f);             // Start with a clean slate.            System.gc();            runtime.runFinalizationSync();            Debug.startAllocCounting();             try {                BufferedReader br                    = new BufferedReader(new InputStreamReader(is), 256);                 int count = 0;                String line;                while ((line = br.readLine()) != null) {                    // Skip comments and blank lines.                    line = line.trim();                    if (line.startsWith("#") || line.equals("")) {                        continue;                    }                     try {                        if (false) {                            Log.v(TAG, "Preloading " + line + "...");                        }                        Class.forName(line);                        //减少GC频率,modify   begin                        if (count%128==0&&Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {//end                            if (false) {                                Log.v(TAG,                                    " GC at " + Debug.getGlobalAllocSize());                            }                            System.gc();                            runtime.runFinalizationSync();                            Debug.resetGlobalAllocSize();                        }                        count++;                    } catch (ClassNotFoundException e) {                        Log.w(TAG, "Class not found for preloading: " + line);                    } catch (UnsatisfiedLinkError e) {                        Log.w(TAG, "Problem preloading " + line + ": " + e);                    } catch (Throwable t) {                        Log.e(TAG, "Error preloading " + line + ".", t);                        if (t instanceof Error) {                            throw (Error) t;                        }                        if (t instanceof RuntimeException) {                            throw (RuntimeException) t;                        }                        throw new RuntimeException(t);                    }                }                 Log.i(TAG, "...preloaded " + count + " classes in "                        + (SystemClock.uptimeMillis()-startTime) + "ms.");            } catch (IOException e) {                Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);            } finally {                IoUtils.closeQuietly(is);                // Restore default.                runtime.setTargetHeapUtilization(defaultUtilization);                 // Fill in dex caches with classes, fields, and methods brought in by preloading.                runtime.preloadDexCaches();                 Debug.stopAllocCounting();                 // Bring back root. We'll need it later.                setEffectiveUser(ROOT_UID);                setEffectiveGroup(ROOT_GID);            }        }    }

3、提升进程的优先级

//    ZygoteInit.java入口    public static void main(String argv[]) {        try {             //优化开机速度 begin            /* 20150127 begin */            //获取当前进程优先级            int currentPriority = Process.getThreadPriority(Process.myPid()) ;            //提升当前进程优先级。            Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO) ;            /* 20150127 end */                        // Start profiling the zygote initialization.            SamplingProfilerIntegration.start();            //1.注册socket服务端            registerZygoteSocket();            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,                SystemClock.uptimeMillis());            //5.加载资源            preload();            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,                SystemClock.uptimeMillis());             // Finish profiling the zygote initialization.            SamplingProfilerIntegration.writeZygoteSnapshot();             // Do an initial gc to clean up after startup            gc();                        /* 20150127 begin */            Process.setThreadPriority(currentPriority) ;            /* 20150127 end */            //优化开机速度 end            // Disable tracing so that forked processes do not inherit stale tracing tags from            // Zygote.            Trace.setTracingEnabled(false);             // If requested, start system server directly from Zygote            if (argv.length != 2) {                throw new RuntimeException(argv[0] + USAGE_STRING);            }          //2. 调用starySystemServer()方法            if (argv[1].equals("start-system-server")) {                startSystemServer();            } else if (!argv[1].equals("")) {                throw new RuntimeException(argv[0] + USAGE_STRING);            }             Log.i(TAG, "Accepting command socket connections");             //3.循环监听并接收客户端请求。            runSelectLoop();            //关闭socket            closeServerSocket();        } catch (MethodAndArgsCaller caller) {          //4  《深入理解Android卷1》作者说这里比较重要            caller.run();        } catch (RuntimeException ex) {            Log.e(TAG, "Zygote died with exception", ex);            closeServerSocket();            throw ex;        }    }

4、修改gc调用阀值

/** when preloading, GC after allocating this many bytes      *      * 20150127 优化开机速度     */        //- private static final int PRELOAD_GC_THRESHOLD = 50000;    private static final int PRELOAD_GC_THRESHOLD = 64*1024*1024;        /*20150127 优化开机速度 end*/

另外,Android系统启动过程中,会预先加载资源文件,这些文件中,包含了很多系统应用会频繁使用到的资源文件,比如图片资源等。因此,我们自己的新添加其他的部分资源也可以预先加载到内存,这样不仅提升响应速度,而且也可以加快应用的冷启动速度(不过对于系统启动速度比较敏感的设备,不建议这么使用)。

5、关于进程优先级

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //设置线程优先级为后台,这样当多个线程并发后很多无关紧要的线程分配的CPU时间将会减少,有利于主线程的处理,有以下几种:

int THREAD_PRIORITY_AUDIO //标准音乐播放使用的线程优先级
int THREAD_PRIORITY_BACKGROUND //标准后台程序
int THREAD_PRIORITY_DEFAULT // 默认应用的优先级
int THREAD_PRIORITY_DISPLAY //标准显示系统优先级,主要是改善UI的刷新
int THREAD_PRIORITY_FOREGROUND //标准前台线程优先级
int THREAD_PRIORITY_LESS_FAVORABLE //低于favorable
int THREAD_PRIORITY_LOWEST //有效的线程最低的优先级
int THREAD_PRIORITY_MORE_FAVORABLE //高于favorable
int THREAD_PRIORITY_URGENT_AUDIO //标准较重要音频播放优先级
int THREAD_PRIORITY_URGENT_DISPLAY //标准较重要显示优先级,对于输入事件同样适用

Thread.setPriority:是JDK提供的设置线程优先级的方法.
android.os.Process.setThreadPriority: 是android.jar 专门针对dalvik来进行设置线程优先级的方法;此方法更适合Android上面设置优先级,它设置的优先级更直接的适应在dalvik(Linux) 上的进程的优先级

注意在使用进行优先级设置的时候,如果提升当前进行的优先级,如果主进程优先级比较低,那么在系统启动过程中当前进程共享 主进程的资源直接导致系统启动延迟。

参考:https://my.oschina.net/kingguary/blog/1573951

         https://blog.csdn.net/xxm282828/article/details/49095839

 

更多相关文章

  1. android异步任务完成后再执行主线程任务
  2. android转屏,切换屏幕,横竖屏(onConfigurationChanged)会重新加载 On
  3. android底图局部加载移动
  4. Android 页面或文件或网络请求时的加载动画
  5. Android使用线程获取网络图片的方法
  6. android中使用多线程——HandlerThread举例
  7. android 多线程断点下载,listview 模式 开始 暂停等功能
  8. [置顶] android中OnScrollListener的详解(Listview分批加载用到)

随机推荐

  1. Android(安卓)RecyclerView Item使用动画
  2. Accessibility辅助功能的使用
  3. OkHttp+Stetho+Chrome调试android网络部
  4. Android一些常用知识和代码(不断更新)
  5. Android检测手机是否插入/连接耳机
  6. 清除Android工程中没用到/未用到的资源
  7. 46、PopWindow工具类
  8. Android之博客案例 及 获取指定URL的网页
  9. 0324安卓如何设置标题栏颜色
  10. android微信付费