(轉)Unity實現c#熱更新方案探究(二)

轉載請標明出處:http://www.cnblogs.com/zblade/

一、IOS對DLL熱更新的禁止
緊接上文,繼續對C#熱更新的研究。上文中,已經說了如何基於appDomain來實現對DLL的加載和卸載,進一步,可以在unity工程中,將Dll打包成資源,通過Assembly.Load的方式加載DLL來實現更新。那麼爲什麼IOS中就不能這樣操作了呢?
推薦閱讀文章:
這兩篇文章,對整個IOS不能熱更新的緣由,有詳細的講解,對於Mono的JIT編譯模式和AOT編譯模式也有講解。總結來說,就是由於IOS的Full AOT編譯模式,不允許在IOS系統中動態生成代碼(代碼是可以在IOS中動態生成的,只是IOS爲了安全性的考慮,禁止了內存的操作權限),所以JIT這種編譯模式被Mono自己就禁止了(IOS下)。
既然不能JIT的編譯,那麼我們就不能基於Assembly.Load來加載DLL的bytes了。如何解決這個問題?讓我們看看ILRuntime的解決思路。
 
二、ILRuntime基於IL虛擬機實現對DLL的熱更新
首先看看ILRuntime對於其實現原理的解釋:
ILRuntime藉助Mono.Cecil庫來讀取DLL的PE信息,以及當中類型的所有信息,最終得到方法的IL彙編碼,然後通過內置的IL解譯執行虛擬機來執行DLL中的代碼
那麼,我們逐步來分析這些操作過程是如何執行的。
1、藉助Mono.Ceil庫來讀取DLL的PE信息以及當中類型的所有信息
這一步是如何實現的,跟隨源代碼做一個詳細的跟蹤。
首先,是構建一個全局的appDomain(這兒不是程序域的意思,只是取其名字意思來表示)

 

 基於WWW的方式加載AssetBundle或者DLL/PDB後,接下來是將其封入到MemoryStream中,將dll和pdb的bytes都存入到內存流中後,執行其內部實現的LoadAssembly方法。

關鍵的是第一行,從Mono中加載模塊:

 
進一步跟蹤:
ReadImageFrom的操作:

 

 其中ImageReader最終來自BinaryReader:
 

那麼接下來的ReadImage操作:

這四個操作,是最核心的操作,分別讀取DLL的PE的各個信息,這樣我們就進入下一個步驟。
2、最終得到方法的IL彙編碼
讓我們分拆來看看這幾個讀取函數的實現
1)ReadOptionalHeaders
主要讀取PE的相關信息,不做過多解釋,可以參看源碼閱讀理解;
2)ReadSections
讀取分塊數據
封裝一個Section,然後去執行讀取,然後賦值給section的Data,注意回退了Index
3)ReadCLIHeader
這步比較簡單

 

4) ReadMetadata

核心是兩個操作,一個是ReadMetadataStream,就是根據不同的標識符來新建不同的存儲結構;一個是ReadTableHeap:

初始化heap中的Table後,進行一次Compute,獲取size:

然後填充size:
基於這四步操作,我們可以將IL的彙編碼存儲到Image中,然後進一步執行後續的CreateModule操作:
具體到,就是:
 
其中的ReadModule爲:
具體的讀取manifest和Module內部數據,可以參看源碼。
讀取完module後,我們下一篇文章再詳細講解如何執行IL語句,這篇文章先寫到這兒吧 :D
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章