成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

極致優(yōu)化 Android 平臺 APK 的大小

移動開發(fā) Android
本篇文章會以Android為例,從各個(gè)方面介紹UE包中的可裁剪部分的優(yōu)化思路與實(shí)踐,同時(shí)優(yōu)化APK大小和Native庫的運(yùn)行時(shí)內(nèi)存占用,其中的策略也可以復(fù)用在其他平臺。

作者 | lipeng

在游戲項(xiàng)目中,當(dāng)我們在打包各個(gè)平臺時(shí),總希望每個(gè)平臺的包能夠最小化便于分發(fā),而且上架某些平臺還有明確的大小要求。對于UE而言,它包含了巨量代碼以及大量的插件,Build階段還將生成反射的膠水代碼,在編譯時(shí)產(chǎn)生了大量的代碼段。以Android平臺為例,將導(dǎo)致libUE4.so的大小急劇增長,對于包體和運(yùn)行時(shí)內(nèi)存都造成了壓力。再加上一些引擎必要和額外帶入的資源也能占據(jù)上百M(fèi),空APK的大小很容易達(dá)到數(shù)百M(fèi)的規(guī)模!不僅僅為了符合上架平臺的要求,從包體和內(nèi)存優(yōu)化的角度,也有必要對UE包的大小進(jìn)行裁剪。

一、包大小分布

在APK內(nèi),游戲相關(guān)的空間占比較大的部分,為下面幾項(xiàng):

  • 可執(zhí)行代碼(so - lib/arm64-v8a)
  • main.obb.png(游戲內(nèi)資源Pak、DirectoriesToAlwaysStageAsNonUFS的部分)
  • 第三方組件拷貝進(jìn)APK內(nèi)的文件

需要分別針對上面列出的三種情況,分別制定具體的優(yōu)化策略。

二、壓縮NativeLibs

當(dāng)APK安裝時(shí),對于NativeLibs有兩種處理方式:

  • 安裝時(shí)解壓so到應(yīng)用的內(nèi)部存儲目錄( /data/app/<package_name>/lib/)
  • 直接從APK文件中加載so,可以加快安裝過程

而它就引出了一個(gè)問題:如果允許安裝時(shí)解壓,則NativeLibs打包進(jìn)APK內(nèi)是可以被執(zhí)行壓縮的。 對比一下實(shí)際的壓縮與否的大小情況,對APK大小的影響非常大:

壓縮

不壓縮

對于原生Android而言,是否在安裝時(shí)解壓NativeLibs是由AndroidManifest.xml中的extractNativeLibs控制的:

<application android:allowBackup="true" android:appComponentFactory="android.support.v4.app.CoreComponentFactory" android:debuggable="true" android:extractNativeLibs="false" android:hardwareAccelerated="true" android:hasCode="true" android:icon="@drawable/icon" android:label="@string/app_name" android:name="com.epicgames.ue4.GameApplication" android:networkSecurityConfig="@xml/network_security_config" android:supportsRtl="true">

在新版引擎中,在AndroidRuntimeSettings配置中直接提供了bExtractNativeLibs的選項(xiàng):

bool bExtractNativeLibs = true;
Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bExtractNativeLibs", out bExtractNativeLibs);

需要注意的是,如果是舊版本引擎(4.27及之前),升級了grable升級后(>4.2)后,gradle用useLegacyPackaging取代extractNativeLibs,Manifest里的extractNativeLibs默認(rèn)是false的,所以會導(dǎo)致APK增大。

解決辦法是可以在UPL中強(qiáng)制把值改了:

<addAttribute tag="application" name="android:extractNativeLibs" value="true"/>

注意:它只是控制讓so打進(jìn)APK時(shí)是否執(zhí)行壓縮,并不會實(shí)際減少so的大??!對于可執(zhí)行程序的優(yōu)化,需要繼續(xù)下面的代碼優(yōu)化的部分。

三、代碼體積優(yōu)化

關(guān)于代碼體積優(yōu)化的部分,在Android平臺,核心目標(biāo)是要減少單個(gè)so的大??!并且盡可能地避免對運(yùn)行時(shí)性能的影響。

對NativeLibs大小優(yōu)化思路:

  • 減少動態(tài)鏈接庫的數(shù)量,剔除不必要的
  • 減少庫內(nèi)部的符號、減少代碼段大小
  • 剔除調(diào)試信息

對于所有的so,都可以在編譯/鏈接時(shí)應(yīng)用這些優(yōu)化策略。 但對于UE項(xiàng)目而言,我們能控制的通常也只有引擎和項(xiàng)目的代碼,庫的代碼需要庫的提供者優(yōu)化。所以接下來的優(yōu)化策略,只針對于libUE4.so/libUnreal.so。

1. 減小libUE4.so

在打包時(shí),因?yàn)樾枰獔?zhí)行完整的編譯,并且UE在運(yùn)行時(shí)默認(rèn)是Monolithic的模式,所有的代碼都被編譯到了同一個(gè)可執(zhí)行文件中。

UE基于UBT的編譯過程封裝,以及提供target.cs/build.cs中的配置參數(shù),使我們能夠在一定程度上對引擎和項(xiàng)目代碼進(jìn)行編譯控制,達(dá)到我們優(yōu)化so大小的目的。

對于UE項(xiàng)目而言,優(yōu)化so的大小有以下幾種思路:

  • 禁用不必要模塊
  • 控制代碼優(yōu)化(控制inline/O3/0z)
  • 禁用Module不必要異常處理
  • 啟用LTO
  • 剔除不需要的導(dǎo)出符號

(1) 禁用模塊

可以把引擎中內(nèi)置的明確不需要使用的模塊在target.cs中關(guān)閉:

// disable modules  
bUseChaos = false;  
bCompileChaos = false;  
bCompileAPEX = false;

同時(shí),需要梳理項(xiàng)目中引入的不必要的運(yùn)行時(shí)插件,減少參與編譯的Module的數(shù)量,從而減少實(shí)際參與編譯的代碼。

(2) 關(guān)閉inline

inline是編譯階段對運(yùn)行時(shí)的執(zhí)行效率優(yōu)化,將函數(shù)調(diào)用直接替換為函數(shù)代碼,而不是常規(guī)的函數(shù)調(diào)用??梢詼p少函數(shù)調(diào)用的開銷,理論上來說可以提高程序的執(zhí)行效率。

但inline會增大.text段的大小,可以酌情關(guān)閉。

  • 修改target.cs:bUseInlining = false;(僅在IOS/Linux/Mac/Win有效)
  • 修改UBT,在Android編譯時(shí)受bUseInlining控制,添加-fno-inline-functions編譯參數(shù)
if (TargetInfo.Platform == UnrealTargetPlatform.Android)
{
 if (bUseInlining)
 {
  AdditionalCompilerArguments += " -finline-functions";
 }else {
  AdditionalCompilerArguments += " -fno-inline-functions";
 }
}

注意:關(guān)閉inline后,如果某些函數(shù)具有高頻調(diào)用,會帶來一些性能損失;在非高頻情況下,inline與否的性能,這個(gè)需要結(jié)合項(xiàng)目的實(shí)際性能情況進(jìn)行控制。在我的測試結(jié)果中,是否inline對幀率影響微乎其微。

(3) 關(guān)閉異常處理

有些模塊中打開了C++異常處理,但是沒有try/catch的使用:

bEnableExceptions = false;

可以關(guān)掉,能夠減少so內(nèi)的.eh_frame的大小。

(4) 使用O3/Oz編譯

在target.cs中控制bCompileForSize的值,可以選擇使用O3或Oz編譯代碼:

// optimization level
if (!CompileEnvironment.bOptimizeCode){
 Result += " -O0";
}else{
 if (CompileEnvironment.bOptimizeForSize){
  Result += " -Oz";
 }else{
  Result += " -O3";
 }
}

O3和Oz的區(qū)別:

  • -O3:性能優(yōu)先,積極內(nèi)聯(lián)、循環(huán)展開
  • -Oz:體積優(yōu)先,避免內(nèi)聯(lián)、保持循環(huán)

可以根據(jù)項(xiàng)目實(shí)際的性能情況,選擇使用哪種方式。

(5) 啟用LTO

LTO是Link Time Optimization的簡稱,可以在鏈接時(shí)剔除死代碼、優(yōu)化跨模塊的函數(shù)調(diào)用、內(nèi)聯(lián)等。 在引擎的build.cs中可以bAllowLTCG打開,LTCG是LTO的一種實(shí)現(xiàn),但是它也只僅在IOS/Linux/Mac/Win有效(UE4.25)。

支持Android的話,同樣也要修改UBT(AndroidToolChain.cs),給Android添加受bAllowLTCG參數(shù)控制,選擇是否添加-flto=thin的編譯參數(shù),thin是縮減大小與優(yōu)化耗時(shí)的綜合版本。

bAllowLTCG = true; // LTO
if (bAllowLTCG)
{
 AdditionalCompilerArguments += "  -flto=thin";
}

(6) 剔除導(dǎo)出符號

在編譯so時(shí),除非特殊設(shè)置,所有的函數(shù)和變量都會被導(dǎo)出,用于被其他的so訪問。 但在UE引擎內(nèi),只有極少數(shù)的接口,是明確被外部訪問的(JNI相關(guān)的接口),所以libUE4.so的符號導(dǎo)出絕大部分是浪費(fèi)的,剔除掉符號導(dǎo)出可以大幅降低so的大小和內(nèi)存占用!

現(xiàn)代編譯器提供了version-script的鏈接時(shí)控制機(jī)制,可以通過傳入一個(gè)ldscript文件來控制鏈接時(shí)的符號行為。

需要在編譯過程中先構(gòu)造出一個(gè)ldscript文件,填入符號導(dǎo)出控制代碼,然后在target.cs中,傳遞給Linker:

string VersionScriptFile = GetVersionScriptFilename();
using (StreamWriter Writer = File.CreateText(VersionScriptFile))
{
 Writer.WriteLine("{ global: Java_*; ANativeActivity_onCreate; JNI_OnLoad; local: *; };");
}
AdditionalLinkerArguments += " -Wl,--version-script=\"" + VersionScriptFile + "\"";

對于UE而言,需要允許導(dǎo)出的只有Java_*/ANativeActivity_onCreate/JNI_OnLoad這三類匹配符號,,其余的均可剔除。

2. 優(yōu)化數(shù)據(jù)

經(jīng)過上面介紹的一系列對代碼體積的優(yōu)化,收益明顯。

(1) so壓縮后大小

前面提到了,NativeLibs進(jìn)APK是可以被壓縮的,所以當(dāng)我們減少了so的原始大小,也能夠減少壓縮后的大小。

經(jīng)過上面的優(yōu)化之后,在Shipping的模式下,so的原始大小從原來的258M減少到了146M! so的壓縮后大小,從74.3M減少到了44.67M,減少了29.63M!可執(zhí)行程序文件顯著減小。

readelf優(yōu)化前后對比(部分?jǐn)?shù)據(jù)):

(2) 內(nèi)存收益

對so大小的優(yōu)化,同時(shí)減少了加載so的內(nèi)存,也能夠獲得額外的內(nèi)存收益。

安卓可以通過dumpsys meminfo來查看整個(gè)包的so占用內(nèi)存情況,包含了所有已加載的so,但可以通過優(yōu)化前后的差值得到實(shí)際的內(nèi)存收益。

優(yōu)化前:

127|PD2324:/ $ dumpsys meminfo com.xxx.yyy
dumpsys meminfo com.xxx.yyy
Applications Memory Usage (in Kilobytes):
Uptime: 501711593 Realtime: 544369467

** MEMINFO in pid 23677 [com.xxx.yyy] **
                   Pss  Private  Private  SwapPss      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
     .so mmap   178165    14024   159220        5   245292

優(yōu)化后:

** MEMINFO in pid 31482 [com.xxx.yyy] **
                   Pss  Private  Private  SwapPss      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
     .so mmap   144041    13208   125644        5   209284

arm64-v8a Shipping

優(yōu)化前

優(yōu)化后

減少

libUE4.so大小

246

145

101

meminfo(so總內(nèi)存)

178.165

140.04

38.125

3. 優(yōu)化策略補(bǔ)充

(1) 重定位表壓縮

① SDK 28

在Android的MinSDKVersion大于等于28時(shí)(Android9),可以在編譯和鏈接時(shí)開啟RELR重定位表壓縮。利用相對地址重定位的特點(diǎn),對重定位信息進(jìn)行高效編碼,從而減少存儲空間占用。

開啟方法,需要在編譯階段給Compiler和Linker傳遞參數(shù):

AdditionalCompilerArguments += " -fPIC";  
AdditionalLinkerArguments += " -Wl,--pack-dyn-relocs=android+relr,--use-android-relr-tags";

-Wl,--pack-dyn-relocs=android+relr,--use-android-relr-tags 是 Android 特有的鏈接器選項(xiàng),它們是對標(biāo)準(zhǔn) -Wl,-z,relro 和 -Wl,-z,now 的補(bǔ)充和優(yōu)化,特別是針對 Android 系統(tǒng)中動態(tài)鏈接和重定位的處理。 它們主要用于進(jìn)一步減小二進(jìn)制文件大小和改善加載時(shí)間。

驗(yàn)證是否生效,可以使用readelf -d libUE4.so,查看是否存在RELR字段:

優(yōu)化前重定位表的大?。?5.82M):

8 .rela.dyn     0189c708  000000000000c720  000000000000c720  0000c720  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rela.plt     00004338  00000000018a8e28  00000000018a8e28  018a8e28  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

優(yōu)化后重定位表的大?。?80K):

8 .rela.dyn     00013852  000000000000c6d8  000000000000c6d8  0000c6d8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .relr.dyn     0002cca8  000000000001ff30  000000000001ff30  0001ff30  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .rela.plt     00004320  000000000004cbd8  000000000004cbd8  0004cbd8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

優(yōu)化后的重定位表大小從25.82M降低到280K,結(jié)果直接體現(xiàn)在so的大小減少了25M,使APK的大小也減少了4M左右,優(yōu)化效果極為明顯。

并且,它對內(nèi)存的優(yōu)化效果也非常顯著:在Development下從190.49M - > 161.06M,減少了29.43M。

優(yōu)化前(Development:190.49MB):

** MEMINFO in pid 16293 [com.xxx.yyy] **
                   Pss  Private  Private  SwapPss      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
     .so mmap   190490    49692   136896        9   255392

優(yōu)化后(Development:161.06MB):

** MEMINFO in pid 16294 [com.xxx.yyy] **
                   Pss  Private  Private  SwapPss      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
     .so mmap   161066    13740   142832        9   227500

它對運(yùn)行時(shí)性能是正面優(yōu)化而不是降低,因?yàn)樗ㄟ^減少運(yùn)行時(shí)重定位的數(shù)量來提高代碼加載速度和降低內(nèi)存占用。

② SDK 23

如果項(xiàng)目對SDK版本有要求,不能升級到28,也可以用另一種替代壓縮參數(shù),要求SDK版本>=23。

AdditionalCompilerArguments += " -fPIC"; 
AdditionalLinkerArguments += " -Wl,--pack-dyn-relocs=android";

它也能夠大幅壓縮重定位表的大小(雖然不如RELE到幾百K的級別),并且也能大幅降低so的內(nèi)存占用:

壓縮后(Development:3.41M):

[ 8] .rela.dyn         LOOS+0x2         000000000000aca0  0000aca0
       000000000033d20e  0000000000000001   A       3     0     8
  [ 9] .rela.plt         RELA             0000000000347eb0  00347eb0
       0000000000004320  0000000000000018   A       3    21     8

運(yùn)行時(shí)的內(nèi)存情況(Development:163.19M),相較于原始190.49M,也降低了27.3M,比RELR略低:

** MEMINFO in pid 11492 [com.tencent.tmgp.fmgame] **
                   Pss  Private  Private  SwapPss      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
     .so mmap   163196    14104   145228        5   228248

③ Shipping內(nèi)存

當(dāng)啟用重定位表壓縮后,Shipping包的總so運(yùn)行時(shí)內(nèi)存降低到了134.74M!

** MEMINFO in pid 13929 [com.xxx.yyy] **
                   Pss  Private  Private  SwapPss      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
     .so mmap   134743    12968   118532        5   198692

四、資源裁剪

1. APK內(nèi)文件

有一些第三方的插件,會往APK內(nèi)拷貝文件,這也是可以優(yōu)化的部分。

需要分析項(xiàng)目的實(shí)際使用情況處理:

  • 剔除不必要的第三方組件
  • 對于必須的組件,剔除不需要的文件

(1) 組件裁剪:以GVoice為例

如果項(xiàng)目集成了GCloud的組件,其中會拷貝至APK文件的組件中,GCloudVoice的模型文件占大頭。

在APK內(nèi)assets/GCloudVoice目錄壓縮后占了約13.5M:

  • wave_dafx_data.bin 是3d語音 不用3d功能可以移除
  • wave_3d_data.bin 是3d語音 不用3d功能可以移除
  • cldnn_spkvector.mnn 提取聲紋的,默認(rèn)不使用這個(gè)功能,可以移除
  • libwxvoiceembed.bin 是文明語音的 不用文明語音可以移除
  • libgvoicensmodel.bin 是噪聲抑制算法模型,不能刪
  • decoder_v4_small.nn、encoder_v4_small.nn aicodec用的 不用aicodec的話可以刪除
  • dse_v1.nn、dse_v1_align.nn、dse_v1_mono.nn 這個(gè)是用于wwise下的新算法資源文件,如果有打包的大小限制,也可以去掉

可以把項(xiàng)目中未用到功能的模型文件剔除。另外從實(shí)現(xiàn)上,最好不要直接刪除文件,而是修改GVoice_APL.xml的拷貝邏輯實(shí)現(xiàn):

<resourceCopies>
    <log text="Start copy res..." />
      <!--
        author: lipengzha
        desc: 只拷貝GVoice的libgvoicensmodel.bin/config.json,其余文件游戲內(nèi)無作用
        原始拷貝代碼:
          <copyDir src="$S(PluginDir)/../GVoiceLib/Android/assets/" dst="$S(BuildDir)/assets"/>
      -->
    <copyFile src="$S(PluginDir)/../GVoiceLib/Android/assets/libgvoicensmodel.bin" dst="$S(BuildDir)/assets/libgvoicensmodel.bin" force="true"/>
    <copyFile src="$S(PluginDir)/../GVoiceLib/Android/assets/config.json" dst="$S(BuildDir)/assets/config.json" force="true"/>
</resourceCopies>

(2) 游戲內(nèi)資源

游戲內(nèi)的資源就是UE引擎或組件依賴的資源/文件,會打包至PAK或拷貝至main.obb內(nèi)的文件。

  • PAK內(nèi):游戲內(nèi)的資產(chǎn),需要梳理哪些是非必要的,哪些是可以剔除或進(jìn)行延遲加載的。
  • DirectoriesToAlwaysStageAsNonUFS:不進(jìn)PAK,但是會打包進(jìn)main.obb里的

(3) PAK內(nèi)資源

更準(zhǔn)確地描述是:安裝包內(nèi)PAK的資源。

引擎必要的資源都在pakchunk0中,除了pakchunk0外,UE可以把利用PrimaryAssetLabel拆分的Chunk打包至安裝包外。

但對于pakchunk0中的資源或文件,依然要進(jìn)行優(yōu)化:

  • 僅保留引擎必要的資源(/Engine中的關(guān)鍵資產(chǎn)、ini、GlobalShader、項(xiàng)目ShaderLibrary、啟動地圖、GameFramework資產(chǎn),等等),在我之前的文章(UE資源管理:引擎打包資源分析)有更詳細(xì)的介紹。
  • 剔除非啟動階段必須的資源
  • 改造引擎延遲加載部分文件(如L10N本地化語言的加載)
  • 拆分啟動階段與游戲內(nèi)資源(如字體),游戲內(nèi)字體單獨(dú)打包且走動態(tài)下載

引擎本身的拆包邏輯也有較大的局限性,比如ShdaerLibrary之類的,默認(rèn)整個(gè)項(xiàng)目生成一個(gè),當(dāng)規(guī)模龐大后,它也將成為優(yōu)化包大小的瓶頸。這部分內(nèi)容的詳情可以查看我之前的另一篇文章(資源管理:重塑UE的包拆分方案)。

除此之外,還需要在資源管理和打包階段,能夠?qū)ndroid的所有資源從安裝包內(nèi)剔除,轉(zhuǎn)為動態(tài)下載/掛載的機(jī)制,并且不能夠影響IOS。 當(dāng)使用諸如PrimaryAssetLabel拆分pak時(shí),引擎為Android提供了內(nèi)置的把Pak從安裝包內(nèi)剔除的方法:

; Config/DefaultEngine.ini
[/Script/AndroidRuntimeSettings.AndroidRuntimeSettings]
+ObbFilters=-*.pak
+ObbFilters=pakchunk0-*

但官方僅在Android平臺有支持,對于其他平臺就沒那么方便了。在之前的文章中曾介紹過,我開發(fā)的HotChunker擴(kuò)展可以很容易地實(shí)現(xiàn)通用的包過濾方案,為全平臺支持自定義的進(jìn)包控制策略。

(4) StageAsNonUFS

在引擎的打包配置中,有一項(xiàng)DirectoriesToAlwaysStageAsNonUFS,它是指定目錄不打包進(jìn)PAK,但是會打包進(jìn)main.obb里的,目前引擎內(nèi)只有Content/Movies目錄會被拷貝至main.obb中。

而在打包時(shí)的讀取的Ini,也是具有層級邏輯的,所以對于打包時(shí)的配置,依然能夠?qū)Σ煌脚_進(jìn)行區(qū)分!如果想要在Android/IOS進(jìn)行區(qū)分,也可以利用這個(gè)機(jī)制做到。

可以把打包策略做如下調(diào)整:除非必要的視頻(如啟動時(shí)立即播放的),可以把其余的游戲內(nèi)MP4單獨(dú)打包時(shí)PAK中,轉(zhuǎn)為動態(tài)下載。

這樣可以大幅減少APK內(nèi)MP4的大小,也能夠使MP4進(jìn)行熱更。

五、優(yōu)化效果

綜合上面多種對包大小優(yōu)化手段后,順利將游戲的APK大小1.23G降低到130M,原始so大小從258M降低到了132M。

運(yùn)行時(shí)內(nèi)存也降低了數(shù)十M!并且包含了完整的第三方組件、游戲功能,資源可走動態(tài)下載,使安裝包本體變成一個(gè)極小化的下載器,便于傳播和分發(fā)。

實(shí)際采用哪些優(yōu)化策略要結(jié)合實(shí)際項(xiàng)目的具體需要,以及對包體大小和性能的平衡來選擇,如inline控制和編譯優(yōu)化級別、資源的極致化裁剪(L10N等)還需要對引擎進(jìn)行改造等。

責(zé)任編輯:趙寧寧 來源: 騰訊技術(shù)工程
相關(guān)推薦

2019-07-25 13:22:43

AndroidAPK文件優(yōu)化

2018-11-30 10:40:15

Android壓縮包大小

2023-01-03 09:33:56

2022-03-11 10:23:02

React性能優(yōu)化

2020-02-19 14:37:11

hashtagRediskey

2013-07-24 16:08:01

Android模擬器Genymotion

2019-07-23 09:20:15

Kafka批量處理客戶端

2023-12-15 17:09:28

.NET8Primitives性能

2022-05-07 15:51:47

Android資源文件文件名

2010-10-12 16:46:18

交換

2020-01-15 11:30:59

編碼優(yōu)化性能

2011-11-08 16:31:10

Java

2021-02-05 15:35:21

Redis數(shù)據(jù)庫命令

2021-09-18 10:07:23

開發(fā)技能代碼

2017-03-02 15:09:29

AndroidAPK瘦身實(shí)踐

2025-04-10 15:53:32

2021-02-02 10:22:48

Web應(yīng)用程序架構(gòu)

2010-02-04 13:52:30

Android ap

2013-05-14 10:39:27

AIR Android打包APK文件
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 日韩精品在线播放 | 伊人春色成人网 | 91视频一区二区三区 | 免费毛片www com cn | 美女一级a毛片免费观看97 | 91精品国产91久久久久久 | 成人福利视频 | 51ⅴ精品国产91久久久久久 | 久久亚洲一区 | 免费黄色的视频 | 久久这里只有精品首页 | 久久久精品一区二区三区 | 在线精品观看 | 久久九七 | 一区福利视频 | av网站在线看 | 91色站| 午夜日韩 | 久久成人国产 | 91国产在线视频在线 | 91精品久久久久久久久久入口 | 久久一级大片 | 成av在线 | 在线国产中文字幕 | 日韩成人精品一区 | 日日骚网 | 亚洲精品白浆高清久久久久久 | 黄色片av | 四虎影 | 国产精品久久一区二区三区 | 亚洲精选一区 | 国产精品二区三区在线观看 | 在线免费观看毛片 | 在线观看成年人视频 | 日韩精品一区二区三区久久 | 成人免费视频播放 | 国产一区二区三区www | 亚洲成人三区 | 国产精品视频导航 | 成人免费视频 | 99精品在线|