微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

1、引言

歲月真是個養豬場,這幾年,人胖了,微信代碼也翻了。

記得 14 年轉崗來微信時,用自己筆記本編譯微信工程才十來分鐘。如今用公司配的 17 年款 27-inch iMac 編譯要接近半小時;偶然間更新完代碼,又莫名其妙需要全新編譯。在這麼低的編譯效率下,開發心情受到嚴重影響。

於是年初我向上頭請示,優化微信編譯效率,上頭也同意了。

微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

學習交流:

- 即時通訊/推送技術開發交流5群:215477170 [推薦]

- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》

(本文同步發佈於:http://www.52im.net/thread-2873-1-1.html)

2、相關文章

《微信團隊分享:微信移動端的全文檢索多音字問題解決方案》

《微信團隊分享:iOS版微信的高性能通用key-value組件技術實踐》

《微信團隊分享:iOS版微信是如何防止特殊字符導致的炸群、APP崩潰的?》

《iOS後臺喚醒實戰:微信收款到賬語音提醒技術總結》

《微信團隊分享:微信Android版小視頻編碼填過的那些坑》

《微信手機端的本地數據全文檢索優化之路》

《微信團隊披露:微信界面卡死超級bug“15。。。。”的來龍去脈》

《微信客戶端團隊負責人技術訪談:如何著手客戶端性能監控和優化》

《微信團隊原創分享:Android版微信從300KB到30MB的技術演進》

《全面總結iOS版微信升級iOS9遇到的各種“坑”》

《Android版微信安裝包“減肥”實戰記錄》

《iOS版微信安裝包“減肥”實戰記錄》

《移動端IM實踐:iOS版微信界面卡頓監測方案》

《移動端IM實踐:iOS版微信小視頻功能技術方案實錄》

《移動端IM實踐:iOS版微信的多設備字體適配方案探討》

《手把手教你讀取Android版微信和手Q的聊天記錄(僅作技術研究學習)》

《微信團隊分享:Kotlin漸被認可,Android版微信的技術嚐鮮之旅》

3、現有方案

在動手之前,先搜索目前已有方案,大概情況如下。

3.1 優化工程配置

1)將 Debug Information Format 改為 DWARF:

Debug 時是不需要生成符號表,可以檢查一下子工程(尤其開源庫)有沒有設置正確。

2)將 Build Active Architecture Only 改為 Yes:

Debug 時是不需要生成全架構,可以檢查一下子工程(尤其開源庫)有沒有設置正確。

3)優化頭文件搜索路徑:

避免工程 Header Search Paths 設置了路徑遞歸引用:

微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

Xcode 編譯源文件時,會根據 Header Search Paths 自動添加 -I 參數,如果遞歸引用的路徑下子目錄越多,-I 參數也越多,編譯器預處理頭文件效率就越低,所以不能簡單的設置路徑遞歸引用。同樣 Framework Search Paths 也類似處理。

3.2 使用 CocoaPods 管理第三方庫

這是業界常用的做法,利用 cocoapods 插件 cocoapods-packager 將任意的 pod 打包成 Static Library,省去重複編譯的時間;但缺點是不方便調試源碼,如果庫代碼反覆修改,需要重新生成二進制並上傳到內部服務器,等等。

3.3 CCache

CCache 是一個能夠把編譯的中間產物緩存起來的工具,不需要過多修改項目配置,也不需要修改開發工具鏈。Xcode 9 有個很偶然的 bug,在源碼沒有任何修改的情況下經常觸發全新編譯,用 CCache 很好的解決這一問題。但隨著 Xcode 10 修復全量編譯問題,這一方案逐步棄用了。

3.4 distcc

distcc 是一個分佈式編譯工具,它原理是把本地多個編譯任務分發到網絡中多個機器,其他機器編譯完成後,再把產物返回給本機上執行鏈接,最終得到編譯結果。

3.5 硬件解決

如把 Derived Data 目錄放到由內存創建的虛擬磁盤,或者購買最新款的 iMac Pro...

4、實踐過程

4.1 優化編譯選項

1)優化頭文件搜索路徑:

把一些遞歸引用路徑去了後,整體編譯速度快了 20s。

2)關閉 Enable Index-While-Building Functionality:

這選項無意中找到的(Xcode 9 的新特性?),默認打開,作用是 Xcode 編譯時會順帶建立代碼索引,但影響編譯速度。關閉後整體編譯速度快 80s(Xcode 會換回以前的方式,在空閒時間建立代碼索引)。

4.2 優化 kinda

kinda 是今年引入支付跨平臺框架(C++),但編譯速度奇慢,一個源文件編譯都要 30s。另外生成的二進制大小在 App 佔比較高,感覺有不少冗餘代碼,理論上減少冗餘代碼也能加快編譯速度。

經過分析 LinkMap 文件和使用 Xcode Preprocess 某些源文件,發現有以下問題:

1)proto 文件生成的代碼較多;

2)某個基類/宏使用了大量模版。

對於問題一:可以設置 proto 文件選項為 optimize_for=CODE_SIZE 來讓 protobuf 編譯器生成精簡版代碼。但我是用自己的工具生成(具體原理可看《iOS版微信安裝包“減肥”實戰記錄》),代碼更少。

對於問題二:由於模版是編譯期間的多態(增加代碼膨脹和編譯時間),所以可以把模版基類改成虛基類這種運行時的多態;另外推薦使用 hyper_function 取代 std::function,使得基類用通用函數指針,就能存儲任意 lambda 回調函數,從而避免基類模板化。

例如:

template<typenamerequest>

classBaseCgi {

public:

BaseCgi(Request request, std::function<void> &callback) {/<void>

_request = request;

_callback = callback;

}


voidonRequest(std::vector<uint8> &outData) {/<uint8>

_request.toData(outData);

}


voidonResponse(std::vector<uint8> &inData) {/<uint8>

Response response;

response.fromData(inData);

callback(response);

}


public:

Request _request;

std::function<void> _callback;/<void>

};


classCgiA : publicBaseCgi<requesta> {/<requesta>

public:

CgiA(RequestA &request, std::function<void> &callback) :/<void>

BaseCgi(request, callback) {}

};

可改成:

class BaseRequest {

public:

virtual void toData(std::vector<uint8> &outData) = 0;/<uint8>

};


classBaseResponse {

public:

virtualvoidfromData(std::vector<uint8> &outData) = 0;/<uint8>

};


classBaseCgi {

public:

template<typenamerequest>

BaseCgi(Request &request, hyper_function<void> callback) {/<void>

_request = newRequest(request);

_response = newResponse;

_callback = callback;

}


voidonRequest(std::vector<uint8> &outData) {/<uint8>

_request->toData(outData);

}


voidonResponse(std::vector<uint8> &inData) {/<uint8>

_response->fromData(inData);

_callback(*_response);

}


public:

BaseRequest *_request;

BaseResponse *_response;

hyper_function<void> _callback;/<void>

};


classRequestA : publicBaseRequest { ... };


classResponseA : publicBaseResponse { ... };


classCgiA : publicBaseCgi {

public:

CgiA(RequestA &request, hyper_function<void> &callback) :/<void>

BaseCgi(request, callback) {}

};

BaseCgi 由模版基類變成只有構造函數是模板的基類,onRequest 和 onResponse 邏輯代碼並不因為基類模版實例化而被“複製黏貼”。

經過上述優化:

整體編譯速度快了 70s,而 kinda 二進制也減少了 60%,效果特別明顯。

4.3 使用 PCH 預編譯頭文件

PCH(Precompile Prefix Header File)文件,也就是預編譯頭文件,其文件裡的內容能被項目中的其他所有源文件訪問。通常放一些通用的宏和頭文件,方便編寫代碼,提高效率。

另外 PCH 文件預編譯完成後,後面用到 PCH 文件的源文件編譯速度也會加快。缺點是 PCH 文件和 PCH 引用到的頭文件內容一旦發生變化,引用到 PCH 的所有源文件都要重新編譯。所以使用時要謹慎。

在 Xcode 裡設置 Prefix Header 和 Precompile Prefix Header 即可使用 PCH 文件並對它進行預編譯:

微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

微信使用 PCH 預編譯後:編譯速度提升非常可觀,快了接近 280s。

5、終極優化

通過上述優化,微信工程的編譯時間由原來的 1,626.4s 下降到 1,182.8s,快了將近 450s,但仍然需要 20 分鐘,令人不滿意。

如果繼續優化,得從編譯器下手。正如我們平常做的客戶端性能優化,在優化之前,先分析原理,輸出每個地方的耗時,針對耗時做相對應的優化。

5.1 編譯原理

編譯器,是把一種語言(通常是高級語言)轉換為另一種語言(通常是低級語言)的程序。

大多數編譯器由三部分組成:

微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

各部分的作用如下:

前端(Frontend):負責解析源碼,檢查錯誤,生成抽象語法樹(AST),並把 AST 轉化成類彙編中間代碼;

優化器(Optimizer):對中間代碼進行架構無關的優化,提高運行效率,減少代碼體積,例如刪除 if (0) 無效分支;

後端(Backend):把中間代碼轉換成目標平臺的機器碼。

LLVM 實現了更通用的編譯框架,它提供了一系列模塊化的編譯器組件和工具鏈。首先它定義了一種 LLVM IR(Intermediate Representation,中間表達碼)。Frontend 把原始語言轉換成 LLVM IR;LLVM Optimizer 優化 LLVM IR;Backend 把 LLVM IR 轉換為目標平臺的機器語言。這樣一來,不管是新的語言,還是新的平臺,只要實現對應的 Frontend 和 Backend,新的編譯器就出來了。

微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

在 Xcode,C/C++/ObjC 的編譯器是 Clang(前端)+LLVM(後端),簡稱 Clang。

Clang 的編譯過程有這幾個階段:

➜ clang -ccc-print-phases main.m

0: input, "main.m", objective-c

1: preprocessor, {0}, objective-c-cpp-output

2: compiler, {1}, ir

3: backend, {2}, assembler

4: assembler, {3}, object

5: linker, {4}, image

6: bind-arch, "x86_64", {5}, image

1)預處理:

這階段的工作主要是頭文件導入,宏展開/替換,預編譯指令處理,以及註釋的去除。

2)編譯:

這階段做的事情比較多,主要有:

a. 詞法分析(Lexical Analysis):將代碼轉換成一系列 token,如大中小括號 paren'()' square'[]' brace'{}'、標識符 identifier、字符串 string_literal、數字常量 numeric_constant 等等;

b. 語法分析(Semantic Analysis):將 token 流組成抽象語法樹 AST;

c. 靜態分析(Static Analysis):檢查代碼錯誤,例如參數類型是否錯誤,調用對象方法是否有實現;

d. 中間代碼生成(Code Generation):將語法樹自頂向下遍歷逐步翻譯成 LLVM IR。

3)生成彙編代碼:

LLVM 將 LLVM IR 生成當前平臺的彙編代碼,期間 LLVM 根據編譯設置的優化級別 Optimization Level 做對應的優化(Optimize),例如 Debug 的 -O0 不需要優化,而 Release 的 -Os 是儘可能優化代碼效率並減少體積。

4)生成目標文件:

彙編器(Assembler)將彙編代碼轉換為機器代碼,它會創建一個目標對象文件,以 .o 結尾。

5)鏈接:

鏈接器(Linker)把若干個目標文件鏈接在一起,生成可執行文件。

5.2 分析耗時

Clang/LLVM 編譯器是開源的,我們可以從官網下載其源碼,根據上述編譯過程,在每個編譯階段埋點輸出耗時,生成定製化的編譯器。在自己準備動手的前一週,國外大神 Aras Pranckevičius 已經在 LLVM 項目提交了 rL357340 修改:clang 增加 -ftime-trace 選項,編譯時生成 Chrome(chrome://tracing) JSON 格式的耗時報告,列出所有階段的耗時。

效果如下:

微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

說明如下:

1)整體編譯(ExecuteCompiler)耗時 8,423.8ms

2)其中前端(Frontend)耗時 5,307.9ms,後端(Backend)耗時 3,009.6ms

3)而前端編譯裡頭文件 SourceA 耗時 xx ms,B 耗時 xx ms,...

4)頭文件處理裡 Parse ClassA 耗時 xx ms,B 耗時 xx ms,...

5)等等

這就是我想要的耗時報告!

接下來修改工程 CC={YOUR PATH}/clang,讓 Xcode 編譯時使用自己的編譯器;同時編譯選項 OTHER_CFLAGS 後面增加 -ftime-trace,每個源文件編譯後輸出耗時報告。

最終把所有報告匯聚起來,形成整體的編譯耗時:

微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

由整體耗時可以看出:

1)編譯器前端處理(Frontend)耗時 7,659.2s,佔整體 87%;

2)而前端處理下頭文件處理(Source)耗時 7,146.2s,佔整體 71.9%!

猜測:頭文件嵌套嚴重,每個源文件都要引入幾十個甚至幾百個頭文件,每個頭文件源碼要做預處理、詞法分析、語法分析等等。實際上源文件不需要使用某些頭文件裡的定義(如 class、function),所以編譯時間才那麼長。

於是又寫了個工具,統計所有頭文件被引用次數、總處理時間、頭文件分組(指一個耗時頂部的頭文件所引用到的所有子頭文件的集合)。

列出一份表格(截取 Top10):

微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

如上表所示:

Header1 處理時間 1187.7s,被引用 2,304 次;

Header2 處理時間 1,124.9s,被引用 3,831 次;

後面 Header3~10 都是被 Header1 引用。

所以可以嘗試優化 TopN 頭文件裡的頭文件引用,儘量不包含其他頭文件。

5.3 解決耗時

通常我們寫代碼時,如果用到某個類,就直接 include 該類聲明所在頭文件,但在頭文件,我們可以用前置聲明解決。

因此優化頭文件思路很簡單:就是能用前置聲明,就用前置聲明替代 include。

實際上改動量非常大:我跟組內另外的同事 vakeee 分工優化 Header1 和 Header2,花了整整 5 個工作日,才改完。效果還是有,整體編譯時間減少 80s。

但需要優化的頭文件還有幾十個,我們不可能繼續做這種體力活。因此我們可以做這樣的工具,通過 AST 找到代碼裡出現的標識符(包括類型、函數、宏),以及標識符定義所在文件,然後分析是否需要 include 它定義所在文件。

先看看代碼如何轉換 AST,如以下代碼:

// HeaderA.h

struct StructA {

intval;

};


// HeaderB.h

structStructB {

intval;

};


// main.c

#include "HeaderA.h"

#include "HeaderB.h"


inttestAndReturn(structStructA *a, structStructB *b) {

returna->val;

}

控制檯輸入:

➜ TestContainer clang -Xclang -ast-dump -fsyntax-only main.c

TranslationUnitDecl 0x7f8f36834208 <<invalid>> <invalid>/<invalid>

|-RecordDecl 0x7faa62831d78 <. line:14:1=""> line:12:8 struct StructA definition

| `-FieldDecl 0x7faa6383da38 <13:2 col:6=""> col:6 referenced val 'int'

|-RecordDecl 0x7faa6383da80 <. line:14:1=""> line:12:8 struct StructB definition

| `-FieldDecl 0x7faa6383db38 <13:2 col:6=""> col:6 val 'int'

`-FunctionDecl 0x7faa6383de50 <35:1 line:37:1=""> line:35:5 testAndReturn 'int (struct StructA *, struct StructB *)'

|-ParmVarDecl 0x7faa6383dc30 <19 col:35=""> col:35 used a 'struct StructA *'

|-ParmVarDecl 0x7faa6383dd40 <38 col:54=""> col:54 b 'struct StructB *'

`-CompoundStmt 0x7faa6383dfc8 <57 line:37:1=""/>

`-ReturnStmt 0x7faa6383dfb8 <36:2 col:12=""/>

`-ImplicitCastExpr 0x7faa6383dfa0 <9 col:12=""> 'int'<lvaluetorvalue>

`-MemberExpr 0x7faa6383df70 <9 col:12=""> 'int'lvalue ->val 0x7faa6383da38

`-ImplicitCastExpr 0x7faa6383df58 <9> 'struct StructA *'<lvaluetorvalue>

`-DeclRefExpr 0x7faa6383df38 <9> 'struct StructA *'lvalue ParmVar 0x7faa6383dc30 'a''struct StructA *'

從上可以看出:每一行包括 AST Node 的類型、所在位置(文件名,行號,列號)和結點描述信息。頭文件定義的類也包含進 AST 中。AST Node 常見類型有 Decl(如 RecordDecl 結構體定義,FunctionDecl 函數定義)、Stmt(如 CompoundStmt 函數體括號內實現)。

微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

Clang AST 有三個重要的基類:ASTFrontendAction、ASTConsumer 以及 RecursiveASTVisitor。

ClangTool 類讀入命令行配置項後初始化 CompilerInstance;CompilerInstance 成員函數 ExcutionAction 會調用 ASTFrontendAction 3 個成員函數 BeginSourceFile(準備遍歷 AST)、Execute(解析 AST)、EndSourceFileAction(結束遍歷)。

ASTFrontendAction 有個重要的純虛函數 CreateASTConsumer(會被自己 BeginSourceFile 調用),用於返回讀取 AST 的 ASTConsumer 對象。

代碼如下:

class MyFrontendAction : public clang::ASTFrontendAction {

public:

virtualstd::unique_ptr<:astconsumer> CreateASTConsumer(clang::CompilerInstance &CI, llvm::StringRef file) override {

TheRewriter.setSourceMgr(CI.getASTContext().getSourceManager(), CI.getASTContext().getLangOpts());

returnllvm::make_unique<myastconsumer>(&CI);/<myastconsumer>

}

};


intmain(intargc, constchar**argv) {

clang::tooling::CommonOptionsParser op(argc, argv, OptsCategory);

clang::tooling::ClangTool Tool(op.getCompilations(), op.getSourcePathList());

intresult = Tool.run(clang::tooling::newFrontendActionFactory<myfrontendaction>().get());/<myfrontendaction>


returnresult;

}

ASTConsumer 有若干個可以 override 的方法,用來接收 AST 解析過程中的回調,其中之一是工具用到的 HandleTranslationUnit 方法。當編譯單元 TranslationUnit 的 AST 完整解析後,HandleTranslationUnit 會被回調。我們在 HandleTranslationUnit 使用 RecursiveASTVisitor 對象以深度優先的方式遍歷 AST 所有結點。

代碼如下:

class MyASTVisitor

: public clang::RecursiveASTVisitor<myastvisitor> {/<myastvisitor>

public:

explicitMyASTVisitor(clang::ASTContext *Ctx) {}


boolVisitFunctionDecl(clang::FunctionDecl* decl) {

// FunctionDecl 下的所有參數聲明允許前置聲明取代 include

// 如上面 Demo 代碼裡 StructA、StructB

returntrue;

}


boolVisitMemberExpr(clang::MemberExpr* expr) {

// 被引用的成員所在的類,需要 include 它定義所在文件

// 如 StructA

returntrue;

}


boolVisitXXX(XXX) {

returntrue;

}


// 同一個類型,可能出現若干次判定結果

// 如果其中一個判斷的結果需要 include,則 include

// 否則使用前置聲明代替 include

// 例如 StructA 只能 include,StructB 可以前置聲明

};


class MyASTConsumer : public clang::ASTConsumer {

private:

MyASTVisitor Visitor;

public:

explicitMyASTConsumer(clang::CompilerInstance *aCI)

: Visitor(&(aCI->getASTContext())) {}


void HandleTranslationUnit(clang::ASTContext &context) override {

clang::TranslationUnitDecl *decl = context.getTranslationUnitDecl();

Visitor.TraverseTranslationUnitDecl(decl);

}

};

工具框架大致如上所示。

不過早在 2011 年 Google 內部做了個基於 Clang libTooling 的工具 include-what-you-use,用來整理 C/C++ 頭文件。

這個工具的使用效果如下:

➜ include-what-you-use main.c

HeaderA.h has correct #includes/fwd-decls)

HeaderB.h has correct #includes/fwd-decls)

main.c should add these lines:

struct StructB;

main.c should remove these lines:

- #include "HeaderB.h" // lines 2-2

The full include-list formain.c:

#include "HeaderA.h" // for StructA

struct StructB;

我們在 IWYU 基礎上,增加了 ObjC 語言的支持,並增強它的邏輯,讓結果更好看(通常 IWYU 處理完後,會引入很多頭文件和前置聲明,我們做剪枝處理,進一步去掉多餘的頭文件和前置聲明,篇幅限制就不多做解釋了)。

微信源碼通過工具優化頭文件引入後,整體編譯時間降到了 710s。另外頭文件依賴的減少,也能降低因修改頭文件引起大規模源碼重編的可能性。

我們再用編譯耗時分析工具分析當前瓶頸:

微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

WCDB 頭文件處理時間太長了,業務代碼(如 Model 類)沒有很好的隔離 WCDB 代碼,把 WINQ 暴露出去,外面被動 include WCDB 頭文件。解決方法有很多,例如 WCDB 相關放 category 頭文件(XXModel+WCDB.h)裡引入,或者跟其他庫一樣,把 放 PCH。

最終編譯時間優化到 540s 以下,是原來的三分之一,編譯效率得到巨大的提升。

6、優化總結

微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

即:

A)優化頭文件搜索路徑;

B)關閉 Enable Index-While-Building Functionality;

C)優化 PB/模版,減少冗餘代碼;

D)使用 PCH 預編譯;

E)使用工具優化頭文件引入;儘量避免頭文件裡包含 C++ 標準庫。

7、未來展望

期待公司的藍盾分佈式編譯 for ObjC;另外可以把業務代碼模塊化,項目文件按模塊加載,目前 kinda/小程序/mars 在很好的實踐中。

8、參考文獻

[1] 如何將 iOS 項目的編譯速度提高5倍

[2] 深入剖析 iOS 編譯 Clang / LLVM

[3] Clang之語法抽象語法樹AST

[4] time-trace: timeline / flame chart profiler for Clang

[5] Introduction to the Clang AST

《微信朋友圈千億訪問量背後的技術挑戰和實踐總結》

《騰訊技術分享:騰訊是如何大幅降低帶寬和網絡流量的(圖片壓縮篇)》

《騰訊技術分享:騰訊是如何大幅降低帶寬和網絡流量的(音視頻技術篇)》

《微信團隊分享:微信移動端的全文檢索多音字問題解決方案》

《騰訊技術分享:Android版手機QQ的緩存監控與優化實踐》

《微信團隊分享:iOS版微信的高性能通用key-value組件技術實踐》

《微信團隊分享:iOS版微信是如何防止特殊字符導致的炸群、APP崩潰的?》

《騰訊技術分享:Android手Q的線程死鎖監控系統技術實踐》

《讓互聯網更快:新一代QUIC協議在騰訊的技術實踐分享》

《iOS後臺喚醒實戰:微信收款到賬語音提醒技術總結》

《騰訊技術分享:社交網絡圖片的帶寬壓縮技術演進之路》

《微信團隊分享:視頻圖像的超分辨率技術原理和應用場景》

《微信團隊分享:微信每日億次實時音視頻聊天背後的技術解密》

《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(上篇)》

《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(下篇)》

《騰訊團隊分享:手機QQ中的人臉識別酷炫動畫效果實現詳解》

《騰訊團隊分享 :一次手Q聊天界面中圖片顯示bug的追蹤過程分享》

《微信團隊分享:微信Android版小視頻編碼填過的那些坑》

《微信手機端的本地數據全文檢索優化之路》

《企業微信客戶端中組織架構數據的同步更新方案優化實戰》

《微信團隊披露:微信界面卡死超級bug“15。。。。”的來龍去脈》

《QQ 18年:解密8億月活的QQ後臺服務接口隔離技術》

《月活8.89億的超級IM微信是如何進行Android端兼容測試的》

《以手機QQ為例探討移動端IM中的“輕應用”》

《一篇文章get微信開源移動端數據庫組件WCDB的一切!》

《微信客戶端團隊負責人技術訪談:如何著手客戶端性能監控和優化》

《微信後臺基於時間序的海量數據冷熱分級架構設計實踐》

《微信後臺團隊:微信後臺異步消息隊列的優化升級實踐分享》

《騰訊原創分享(一):如何大幅提升移動網絡下手機QQ的圖片傳輸速度和成功率》

《騰訊原創分享(二):如何大幅壓縮移動網絡下APP的流量消耗(下篇)》

《騰訊原創分享(三):如何大幅壓縮移動網絡下APP的流量消耗(上篇)》

《微信Mars:微信內部正在使用的網絡層封裝庫,即將開源》

《如約而至:微信自用的移動端IM網絡層跨平臺組件庫Mars已正式開源》

《開源libco庫:單機千萬連接、支撐微信8億用戶的後臺框架基石 [源碼下載]》

《微信新一代通信安全解決方案:基於TLS1.3的MMTLS詳解》

《微信團隊原創分享:Android版微信後臺保活實戰分享(進程保活篇)》

《微信團隊原創分享:Android版微信後臺保活實戰分享(網絡保活篇)》

《Android版微信從300KB到30MB的技術演進(PPT講稿) [附件下載]》

《微信團隊原創分享:Android版微信從300KB到30MB的技術演進》

《微信技術總監談架構:微信之道——大道至簡(演講全文)》

《微信技術總監談架構:微信之道——大道至簡(PPT講稿) [附件下載]》

《如何解讀《微信技術總監談架構:微信之道——大道至簡》》

《微信海量用戶背後的後臺系統存儲架構(視頻+PPT) [附件下載]》

《微信異步化改造實踐:8億月活、單機千萬連接背後的後臺解決方案》

《微信朋友圈海量技術之道PPT [附件下載]》

《微信對網絡影響的技術試驗及分析(論文全文)》

《一份微信後臺技術架構的總結性筆記》

《架構之道:3個程序員成就微信朋友圈日均10億發佈量[有視頻]》

《快速裂變:見證微信強大後臺架構從0到1的演進歷程(一)》

《快速裂變:見證微信強大後臺架構從0到1的演進歷程(二)》

《全面總結iOS版微信升級iOS9遇到的各種“坑”》

《微信團隊原創Android資源混淆工具:AndResGuard [有源碼]》

《Android版微信安裝包“減肥”實戰記錄》

《iOS版微信安裝包“減肥”實戰記錄》

《移動端IM實踐:iOS版微信界面卡頓監測方案》

《移動端IM實踐:iOS版微信小視頻功能技術方案實錄》

《移動端IM實踐:Android版微信如何大幅提升交互性能(一)》

《移動端IM實踐:Android版微信如何大幅提升交互性能(二)》

《移動端IM實踐:實現Android版微信的智能心跳機制》

《移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》

《移動端IM實踐:谷歌消息推送服務(GCM)研究(來自微信)》

《移動端IM實踐:iOS版微信的多設備字體適配方案探討》

《信鴿團隊原創:一起走過 iOS10 上消息推送(APNS)的坑》

《騰訊信鴿技術分享:百億級實時消息推送的實戰經驗》

《IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)》

《IPv6技術詳解:基本概念、應用現狀、技術實踐(下篇)》

《騰訊TEG團隊原創:基於MySQL的分佈式數據庫TDSQL十年鍛造經驗分享》

《微信多媒體團隊訪談:音視頻開發的學習、微信的音視頻技術和挑戰等》

《瞭解iOS消息推送一文就夠:史上最全iOS Push技術詳解》

《騰訊技術分享:微信小程序音視頻技術背後的故事》

《騰訊資深架構師乾貨總結:一文讀懂大型分佈式系統設計的方方面面》

《微信多媒體團隊梁俊斌訪談:聊一聊我所瞭解的音視頻技術》

《騰訊音視頻實驗室:使用AI黑科技實現超低碼率的高清實時視頻聊天》

《騰訊技術分享:微信小程序音視頻與WebRTC互通的技術思路和實踐》

《手把手教你讀取Android版微信和手Q的聊天記錄(僅作技術研究學習)》

《微信技術分享:微信的海量IM聊天消息序列號生成實踐(算法原理篇)》

《微信技術分享:微信的海量IM聊天消息序列號生成實踐(容災方案篇)》

《騰訊技術分享:GIF動圖技術詳解及手機QQ動態表情壓縮技術實踐》

《微信團隊分享:Kotlin漸被認可,Android版微信的技術嚐鮮之旅》

《社交軟件紅包技術解密(一):全面解密QQ紅包技術方案——架構、技術實現等》

《社交軟件紅包技術解密(二):解密微信搖一搖紅包從0到1的技術演進》

《社交軟件紅包技術解密(三):微信搖一搖紅包雨背後的技術細節》

《社交軟件紅包技術解密(四):微信紅包系統是如何應對高併發的》

《社交軟件紅包技術解密(五):微信紅包系統是如何實現高可用性的》

《社交軟件紅包技術解密(六):微信紅包系統的存儲層架構演進實踐》

《社交軟件紅包技術解密(九):談談手Q紅包的功能邏輯、容災、運維、架構等》

《QQ設計團隊分享:新版 QQ 8.0 語音消息改版背後的功能設計思路》

《微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結》

>> 更多同類文章 ……

(本文同步發佈於:http://www.52im.net/thread-2873-1-1.html)


分享到:


相關文章: