轉自: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