先從一張架構(gòu)預(yù)覽圖說起吧:
Flutter架構(gòu)分Framework/Engine/Embedder三層:
Framework
Framework層是純dart語言寫的,它實現(xiàn)了一套用于處理Animation、Painting和Gestures的基礎(chǔ)功能,并基于Painting封裝了一套widget用來抹平跨平臺UI展示的差異
以及提供了一套減少由于UI改變控件重復(fù)創(chuàng)建銷毀帶來的性能消耗
Embedder層
什么是Embedder ?
個人理解是flutter想要在不同的平臺上運行就要在不同的平臺上創(chuàng)建容器詳情點擊這里
比如在Android上就要創(chuàng)建FlutterActivity/FlutterFragment/FlutterView
通過查看源碼可以發(fā)現(xiàn)Embedder層主要負(fù)責(zé) Engine的初始化 線程設(shè)置 渲染組件的設(shè)置 資源文件的初始化
Engine層
Engine層是由C++編寫是flutter的核心負(fù)責(zé)初始化,Dart虛擬機管理,F(xiàn)lutter底層的通信和事件機制
Embedder如何和Engine建立關(guān)系
跟蹤FlutterEmbedder層代碼中會發(fā)現(xiàn)不論是FlutterActivity還是FlutterFragment最終Flutter的容器還是FlutterView,而FlutterView只不過繼承了SurfaceView
/**
* An Android view containing a Flutter app.
*/
public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry {
//...
if (nativeView == null) {
mNativeView = new FlutterNativeView(activity.getApplicationContext());
} else {
mNativeView = nativeView;
}
dartExecutor = mNativeView.getDartExecutor();
flutterRenderer = new FlutterRenderer(mNativeView.getFlutterJNI());
//...
mNativeView.attachViewAndActivity(this, activity);
mSurfaceCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
assertAttached();
mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
assertAttached();
mNativeView.getFlutterJNI().onSurfaceChanged(width, height);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
assertAttached();
mNativeView.getFlutterJNI().onSurfaceDestroyed();
}
};
getHolder().addCallback(mSurfaceCallback);
// ...
}
surface的改變會通知nativeview,F(xiàn)lutterView好像就是nativeview的裝飾器,那么讓我們進(jìn)入FlutterNativeView看看:
public FlutterNativeView(@NonNull Context context, boolean isBackgroundView) {
//...
mFlutterJNI = new FlutterJNI();
//...構(gòu)造后直接調(diào)用attach方法調(diào)用和Engine層建立關(guān)系
attach(this, isBackgroundView);
}
FlutterJNI getFlutterJNI() {
return mFlutterJNI;
}
private void attach(FlutterNativeView view, boolean isBackgroundView) {
mFlutterJNI.attachToNative(isBackgroundView);
dartExecutor.onAttachedToJNI();
}
由此可以看出Navtive是通過FlutterJNI和JNI層關(guān)聯(lián)并初始化Engine
關(guān)聯(lián)并Engine初始化
attachToNative 的代碼位置在這里:/flutter/shell/platform/android/platform_view_android_jni.cc
static jlong AttachJNI(JNIEnv* env,
jclass clazz,
jobject flutterJNI,
jboolean is_background_view) {
fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterJNI);
auto shell_holder = std::make_unique<AndroidShellHolder>(
FlutterMain::Get().GetSettings(), java_object, is_background_view);
if (shell_holder->IsValid()) {
return reinterpret_cast<jlong>(shell_holder.release());
} else {
return 0;
}
}
reinterpret_cast是C++里的強制類型轉(zhuǎn)換符。這里reinterpret_cast()方法將該AndroidShellHolder對象指針強制轉(zhuǎn)化為long類型的值并返回java層保存。
那就從AndroidShellHolder分析:/flutter/shell/platform/android/android_shell_holder.cc
step1: 創(chuàng)建四個線程 并把當(dāng)前線程設(shè)置platform thread
// The current thread will be used as the platform thread. Ensure that the
// message loop is initialized.
fml::MessageLoop::EnsureInitializedForCurrentThread();
fml::RefPtr<fml::TaskRunner> gpu_runner;
fml::RefPtr<fml::TaskRunner> ui_runner;
fml::RefPtr<fml::TaskRunner> io_runner;
fml::RefPtr<fml::TaskRunner> platform_runner =
fml::MessageLoop::GetCurrent().GetTaskRunner();
if (is_background_view) {
...
} else {
gpu_runner = thread_host_.gpu_thread->GetTaskRunner();
ui_runner = thread_host_.ui_thread->GetTaskRunner();
io_runner = thread_host_.io_thread->GetTaskRunner();
}
blink::TaskRunners task_runners(thread_label, // label
platform_runner, // platform
gpu_runner, // gpu
ui_runner, // ui
io_runner // io
);
step2:
shell_ =
Shell::Create(task_runners, // task runners
settings_, // settings
on_create_platform_view, // platform view create callback
on_create_rasterizer // rasterizer create callback
);
/flutter/shell/common/shell.cc
如果編譯Engine不方便方便可在github直接查看
std::unique_ptr<Shell> Shell::Create(
TaskRunners task_runners,
Settings settings,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
PerformInitializationTasks(settings);
PersistentCache::SetCacheSkSL(settings.cache_sksl);
TRACE_EVENT0("flutter", "Shell::Create");
auto vm = DartVMRef::Create(settings);
FML_CHECK(vm) << "Must be able to initialize the VM.";
auto vm_data = vm->GetVMData();
return Shell::Create(std::move(task_runners), //
std::move(settings), //
vm_data->GetIsolateSnapshot(), // isolate snapshot
DartSnapshot::Empty(), // shared snapshot
std::move(on_create_platform_view), //
std::move(on_create_rasterizer), //
std::move(vm) //
);
}
//...
std::unique_ptr<Shell> Shell::Create(
TaskRunners task_runners,
Settings settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
fml::RefPtr<const DartSnapshot> shared_snapshot,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer,
DartVMRef vm) {
//...
shell = CreateShellOnPlatformThread(std::move(vm),
std::move(task_runners), //
settings, //
std::move(isolate_snapshot), //
std::move(shared_snapshot), //
on_create_platform_view, //
on_create_rasterizer //
);
//...
}
1根據(jù)setting執(zhí)行了初始化Task
2創(chuàng)建了DartVM并將其傳入Shell的Create方法中
在這里找到Shell真正的Create方法CreateShellOnPlatformThread
// Create the rasterizer on the GPU thread.
// Create the platform view on the platform thread (this thread).
// Ask the platform view for the vsync waiter. This will be used by the engine
auto vsync_waiter = platform_view->CreateVSyncWaiter();
// Create the IO manager on the IO thread.
// Create the engine on the UI thread.
根據(jù)代碼注釋可知:
1 在GPUThread創(chuàng)建rasterizer
2 在platform thread(APP主線程) 創(chuàng)建PlatformView 并獲取其VSyncWaiter傳遞給Engine
3 在UIThread創(chuàng)建Engine
然后通過shell的Setup方法調(diào)用將platform_view、io_manager、rasterizer和engine四個unique_ptr保存到Shell對象中交由Shell對象管理并將Create的結(jié)果shell返回給AndroidShellHolder 由此Embedder層和Engine層就建立了聯(lián)系 并初始化了 四個線程 一個DartVM 和一個Engine。
這里畫了一個圖總結(jié)一下:
Flutter與線程
Flutter Engine自己不創(chuàng)建, 管理線程。Flutter Engine線程的創(chuàng)建和管理是由embedder負(fù)責(zé)的
Embeder提供四個Task Runner, 每個Task Runner負(fù)責(zé)不同的任務(wù),F(xiàn)lutter Engine不在乎Task Runner具體跑在哪個線程,但是它需要線程配置在整一個生命周期里面保持穩(wěn)定。也就是說一個Runner最好始終保持在同一線程運行
Platform Task Runner
根據(jù)代碼在初始化Engine的時候,將當(dāng)前線程設(shè)置為PlatformTaskRunner的Thread,是Flutter和Native交互的橋梁,而且官方要求所有和Flutter的交互必須發(fā)生在PlatformThread中,因為FlutterEngine中有很多模塊是非線程安全的,所以如果在其他線程調(diào)用Flutter engine會出現(xiàn)無法預(yù)期的異常
然是值得注意的是,PlatformThread阻塞并不會直接導(dǎo)致Flutter應(yīng)用卡頓,因為Flutter渲染的核心在UIThread中
UI Task Runner
前文中Embedder和Engine關(guān)聯(lián)后,Engine就開始著手執(zhí)行Dart root isolate代碼 ,Root Isolate負(fù)責(zé)創(chuàng)建管理的Layer Tree最終決定什么內(nèi)容要繪制到屏幕上。因此這個線程的過載會直接導(dǎo)致卡頓掉幀。
GPU Task Runner
GPU Task Runner中的模塊負(fù)責(zé)將Layer Tree提供的信息轉(zhuǎn)化為實際的GPU指令。GPU Task Runner同時也負(fù)責(zé)配置管理每一幀繪制所需要的GPU資源,這包括平臺Framebuffer的創(chuàng)建,Surface生命周期管理,保證Texture和Buffers在繪制的時候是可用的。
GPU Runner可以導(dǎo)致UI Runner的幀調(diào)度的延遲,GPU Runner的過載會導(dǎo)致Flutter應(yīng)用的卡頓。一般來說用戶沒有機會向GPU Runner直接提交任務(wù),因為平臺和Dart代碼都無法跑進(jìn)GPU Runner。但是Embeder還是可以向GPU Runner提交任務(wù)的。因此建議為每一個Engine實例都新建一個專用的GPU Runner線程。
IO Task Runner
主要功能是從圖片存儲(比如磁盤)中讀取壓縮的圖片格式,將圖片數(shù)據(jù)進(jìn)行處理為GPU Runner的渲染做好準(zhǔn)備。
總結(jié):
Platform Thread | GPU Thread | UI Thread | IO Thread |
---|---|---|---|
Flutter Engine的接口調(diào)用 | 執(zhí)行設(shè)備GPU的指令 | 執(zhí)行Dart root isolate代碼 | 讀取并處理圖片數(shù)據(jù) |
isolate
isolate是隔離的,每個isolate有自己的內(nèi)存和單線程運行的實體. isolate之間不互相共享內(nèi)存,且獨立GC。
isolate中的代碼是順序執(zhí)行的,且是單線程,所以不存在資源競爭和變量狀態(tài)同步的問題,也就不需要鎖。Dart中的并發(fā)都是多個isolate并行實現(xiàn)的
由于isolate不共享內(nèi)存,所以isolate之間不能直接互相通信,只能通過Port進(jìn)行通信,而且是異步的
Flutter Engine Runners與Dart Isolate
Dart的Isolate是Dart虛擬機自己管理的,F(xiàn)lutter Engine無法直接訪問。Root Isolate通過Dart的C++調(diào)用能力把UI渲染相關(guān)的任務(wù)提交到UI Runner執(zhí)行, 這樣就可以跟Flutter Engine相關(guān)模塊進(jìn)行交互,F(xiàn)lutter UI相關(guān)的任務(wù)也被提交到UI Runner也可以相應(yīng)的給Isolate一些事件通知, Dart isolate跟Flutter Runner是相互獨立的,它們通過任務(wù)調(diào)度機制相互協(xié)作
DalvikVM與DartVM
DartVM的內(nèi)存管理
準(zhǔn)確的說DartVM和JVM的GC機制相似 使用分年代收集的方式,將內(nèi)存分為新生代和老年代:
新生代
初次分配的對象都位于新生代中,該區(qū)域主要是存放內(nèi)存較小并且生命周期較短的對象,比如局部變量。新生代會頻繁執(zhí)行內(nèi)存回收(GC),回收采用“復(fù)制-清除”算法,將內(nèi)存分為兩塊,運行時每次只使用其中的一塊,另一塊備用。當(dāng)發(fā)生GC時,將當(dāng)前使用的內(nèi)存塊中存活的對象拷貝到備用內(nèi)存塊中,然后清除當(dāng)前使用內(nèi)存塊,最后,交換兩塊內(nèi)存的角色。
老年代
老年代GC采用的是標(biāo)記-清理的方式而且在標(biāo)記的時候,該線程中內(nèi)存區(qū)域是處于不可修改的狀態(tài),類似于JVM中stop the world,但是由于dart優(yōu)秀的schedule機制和老年代GC頻率很低的原因,基本上不會出現(xiàn)這個問題。
schedule
在查看engine源碼的過程中我們看到,dartVM被作為一個變量傳入了engine,為了最小化GC對APP和UI的性能影響,當(dāng)FlutterApp處于空閑/無用戶交互/后臺的情況下,engine調(diào)用DartVM觸發(fā)GC
isolate
記得在JVM中Thread是執(zhí)行操作的最小單元,Dart區(qū)別于JVM的是:
isolate有自己獨立的堆棧
isolate之間內(nèi)存不共享
isolate之間GC不會相互影響
isolate之間不能直接相互通信,只能通過Port進(jìn)行異步通信
整個Flutter Framework Widget的渲染過程都運行在一個isolate中
由此可見Dart天生不存在數(shù)據(jù)競爭和變量不同步的問,或者說Dart是單線程的,可是在移動端,APP大多數(shù)時間是處于等待的狀態(tài):等待網(wǎng)絡(luò)請求結(jié)果,等待用戶操作等因此Flutter選擇Dart作為開發(fā)語言也有一定的道理。