<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Jack Jiang

    我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
    posts - 494, comments - 13, trackbacks - 0, articles - 1

    1、引言

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

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

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

     
     

    學習交流:

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

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

    (本文同步發布于:http://www.52im.net/thread-2873-1-1.html

    2、相關文章

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

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

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

    微信團隊原創分享:iOS版微信的內存監控系統技術實踐

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

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

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

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

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

    微信團隊原創分享:Android版微信的臃腫之困與模塊化實踐之路

    微信團隊原創分享:微信客戶端SQLite數據庫損壞修復實踐

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

    微信團隊原創分享:Android內存泄漏監控和優化技巧總結

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

    微信團隊原創資源混淆工具:讓你的APK立減1M

    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 設置了路徑遞歸引用:

    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, typenameResponse>

    classBaseCgi {

    public:

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

            _request = request;

            _callback = callback;

        }

     

        voidonRequest(std::vector<uint8_t> &outData) {

            _request.toData(outData);

        }

     

        voidonResponse(std::vector<uint8_t> &inData) {

            Response response;

            response.fromData(inData);

            callback(response);

        }

     

    public:

        Request _request;

        std::function<void(Response &)> _callback;

    };

     

    classCgiA : publicBaseCgi<RequestA, ResponseA> {

    public:

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

            BaseCgi(request, callback) {}

    };

    可改成:

    class BaseRequest {

    public:

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

    };

     

    classBaseResponse {

    public:

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

    };

     

    classBaseCgi {

    public:

        template<typenameRequest, typenameResponse>

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

            _request = newRequest(request);

            _response = newResponse;

            _callback = callback;

        }

     

        voidonRequest(std::vector<uint8_t> &outData) {

            _request->toData(outData);

        }

     

        voidonResponse(std::vector<uint8_t> &inData) {

            _response->fromData(inData);

            _callback(*_response);

        }

     

    public:

        BaseRequest *_request;

        BaseResponse *_response;

        hyper_function<void(BaseResponse &)> _callback;

    };

     

    classRequestA : publicBaseRequest { ... };

     

    classResponseA : publicBaseResponse { ... };

     

    classCgiA : publicBaseCgi {

    public:

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

            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 文件并對它進行預編譯: 

    微信使用 PCH 預編譯后:編譯速度提升非??捎^,快了接近 280s。

    5、終極優化

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

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

    5.1 編譯原理

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

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

    各部分的作用如下:

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

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

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

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

    在 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 格式的耗時報告,列出所有階段的耗時。

    效果如下: 

    說明如下:

    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,每個源文件編譯后輸出耗時報告。

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

    由整體耗時可以看出:

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

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

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

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

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

    如上表所示:

    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 sloc>> <invalid sloc>

    |-RecordDecl 0x7faa62831d78 <./HeaderA.h:12:1, line:14:1> line:12:8 struct StructA definition

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

    |-RecordDecl 0x7faa6383da80 <./HeaderB.h:12:1, line:14:1> line:12:8 struct StructB definition

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

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

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

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

      `-CompoundStmt 0x7faa6383dfc8 <col:57, line:37:1>

        `-ReturnStmt 0x7faa6383dfb8 <line:36:2, col:12>

          `-ImplicitCastExpr 0x7faa6383dfa0 <col:9, col:12> 'int'<LValueToRValue>

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

              `-ImplicitCastExpr 0x7faa6383df58 <col:9> 'struct StructA *'<LValueToRValue>

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

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

     

    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<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &CI, llvm::StringRef file) override {

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

            returnllvm::make_unique<MyASTConsumer>(&CI);

        }

    };

     

    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());

     

        returnresult;

    }

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

    代碼如下:

    class MyASTVisitor

    : public clang::RecursiveASTVisitor<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。另外頭文件依賴的減少,也能降低因修改頭文件引起大規模源碼重編的可能性。

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

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

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

    6、優化總結

    總結微信的編譯優化方案:

    即:

    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

    附錄:QQ、微信團隊原創技術文章匯總

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

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

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

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

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

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

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

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

    微信團隊原創分享:iOS版微信的內存監控系統技術實踐

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    微信后臺基于時間序的海量數據冷熱分級架構設計實踐

    微信團隊原創分享:Android版微信的臃腫之困與模塊化實踐之路

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

    微信團隊原創分享:微信客戶端SQLite數據庫損壞修復實踐

    騰訊原創分享(一):如何大幅提升移動網絡下手機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的演進歷程(二)

    微信團隊原創分享:Android內存泄漏監控和優化技巧總結

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

    微信團隊原創資源混淆工具:讓你的APK立減1M

    微信團隊原創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



    作者:Jack Jiang (點擊作者姓名進入Github)
    出處:http://www.52im.net/space-uid-1.html
    交流:歡迎加入即時通訊開發交流群 215891622
    討論:http://www.52im.net/
    Jack Jiang同時是【原創Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
    本博文 歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
    主站蜘蛛池模板: 四虎国产精品免费永久在线| 国内大片在线免费看| 亚洲黄片毛片在线观看| 亚洲AV无码乱码在线观看代蜜桃 | 性感美女视频免费网站午夜 | 东方aⅴ免费观看久久av| 国产极品粉嫩泬免费观看 | 亚洲视频免费一区| 国产亚洲视频在线播放| 激情小说亚洲色图| 久久国内免费视频| 亚洲综合激情九月婷婷 | 亚洲日本乱码在线观看| 羞羞网站免费观看| 日本无吗免费一二区| 亚洲色欲色欲www| 最近免费2019中文字幕大全| 亚洲乱码中文字幕久久孕妇黑人 | 麻豆国产人免费人成免费视频| 亚洲日韩国产精品无码av| 嫩草在线视频www免费观看 | 亚洲AV无码一区二区二三区入口| 羞羞视频在线观看免费| 国产免费人成视频在线观看| 亚洲色欲色欱wwW在线| 国产91免费在线观看| 久久青青草原亚洲av无码app| 中文字幕无线码中文字幕免费| 亚洲国产黄在线观看| AV激情亚洲男人的天堂国语| 四虎成人免费网站在线| 亚洲人成77777在线观看网| 99久久99这里只有免费费精品| 久久亚洲日韩看片无码| 香蕉免费一区二区三区| 亚洲av无码不卡| 免费黄网站在线看| 亚洲人成在线影院| 99国产精品免费观看视频| 亚洲一区免费观看| 8x网站免费入口在线观看|