안드로이드 부팅 최적화 (프리로드 클래스 및 자원의 최적화)

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

클래스 및 자원 섹션 안드로이드 부팅 프로세스가 비교적 긴 시간이 소요되는,이 부분은 주로 문서 관련, 최적화 할 필요가 미리로드 :

./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*/

또한, 안드로이드 시스템 시작은 리소스 파일을 미리로드, 이러한 문서는 이미지 및 기타 자원 자주 리소스 파일을 사용하는 시스템 응용 프로그램을 많이 포함되어 있습니다. 따라서 단지 콜드 스타트 ​​속도 응용 프로그램의 속도를 높일 수 있습니다 또한 응답 속도를 향상 있지만 있도록 자원을 우리 자신의 새로운 추가 다른 부분도 사전에 메모리에로드 할 수있다 (하지만 더 민감한 시스템 부팅 속도 장비, 이러한 사용을 권장하지 않습니다).

5, 처리 우선 순위에

Process.setThreadPriority (Process.THREAD_PRIORITY_BACKGROUND)는, 복수의 병행 thread 후 줄어들 것입니다 CPU 시간의 많은 스레드 할당 문제가되지 않을 때, 그래서 메인 스레드의 처리를 용이하게, 다음과 같다을 배경 스레드 우선 순위를 설정 // :

INT THREAD_PRIORITY_AUDIO // 스레드 우선 순위 표준 음악 플레이어 사용
INT THREAD_PRIORITY_BACKGROUND // 표준 데몬
INT THREAD_PRIORITY_DEFAULT // 기본 응용 프로그램의 우선 순위
INT THREAD_PRIORITY_DISPLAY // 표준 디스플레이 시스템 우선 순위는 UI 새로 고침 개선하기 위해 주로
THREAD_PRIORITY_FOREGROUND // 표준 리셉션 INT를 스레드 우선 순위
INT THREAD_PRIORITY_LESS_FAVORABLE // 유리한 아래
INT THREAD_PRIORITY_LOWEST // 유효한 스레드 우선 순위가 가장 낮은
INT THREAD_PRIORITY_MORE_FAVORABLE // 유리한 위
INT THREAD_PRIORITY_URGENT_AUDIO // 더 중요한 표준 오디오 재생 우선 순위
INT THREAD_PRIORITY_URGENT_DISPLAY // 더 중요한 표준 디스플레이 우선 순위, 동일한 입력 이벤트에 대한 적용

. (자), Thread.setPriority : 설정 스레드 우선 순위는 JDK 의해 제공된 방법
Android.os.Process.setThreadPriority : android.jar 스레드 우선 순위 방식을 설정 달빅 위해 설계되고,이 방법은 안드로이드 상위 우선 순위를 설정하는 더 적합 그것을 달빅 (리눅스)의 직접적인 적응 프로세스에 우선 순위를 설정하는 것은 우선 순위

우선 순위 설정을 사용하면 프로세스의 주요 우선 순위가 상대적으로 낮은 경우 우선 순위의 지속적인 업그레이드, 다음 시스템 시작 자원 중 주요 공정을 공유하는 현재 프로세스가 시스템 시작 지연에 직접 주도 경우 해당 주.

참조 : https://my.oschina.net/kingguary/blog/1573951

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

 

추천

출처blog.csdn.net/jinron10/article/details/89315392