在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

安卓動態鏈接庫文件體積優化探索實踐

京東云 ? 來源:jf_75140285 ? 作者:jf_75140285 ? 2024-11-21 14:07 ? 次閱讀

作者:CCO體系 尚紅澤

背景介紹

應用安裝包的體積影響著用戶下載量、安裝時長、用戶磁盤占用量等多個方面,據Google Play統計,應用體積每增加6MB,安裝的轉化率將下降1%。

安裝包的體積受諸多方面影響,針對dex、資源文件、so文件都有不同的優化策略,在此不做一一展開,本文主要記錄了在研發時針對動態鏈接庫的文件體積裁剪優化方案。

我開發的鏈接庫使用rust語言開發,通過安卓jni接口實現java層和native層之間的相互調用。為什么使用rust主要有以下幾個方面的考慮:

1.穩。安卓的JNI接口調用復雜,又涉及到native層的內存管理,隨著代碼量的增加,代碼的安全穩定性會受到很大的挑戰。使用rust開發,開發者幾乎不需要考慮GC的問題,只要開發的時候按照規范老老實實寫代碼并且通過了編譯器的檢查,基本上就很難把程序寫崩,這一點在代碼上線后也確實得到了驗證。

2.安全。傳統使用C、C++開發的代碼編譯完成以后,如果不加保護,很容易使用反匯編工具破解,市面上比較成熟的工具如IDA、ghidra等都可以將匯編代碼還原到高級語言。使用rust編譯的產物,內部函數間的調用規約和傳統都不一樣,目前市面上還沒有相對完善的反編譯工具,軟件的防破解能力直接上升一個數量級。

但是使用rust有一個非常明顯的缺點就是編譯產物體積過大。在不修改默認的rust編譯選項的情況下,僅開啟strip的情況下,我的動態庫體積達到了495k。

優化方案

參考網上前人的經驗,依次進行了以下優化方式。

調整優化等級

默認的編譯優化等級是O3,該優化的目的提高代碼的運行速度,但是與此同時會對部分循環進行展開,體積造成膨脹。在此我們以縮減體積為目標,將優化選項改為z,表示生成最小二進制體積:

[profile.release] opt-level = 'z'

優化后前后體積變化

編譯選項 體積
strip 495k
strip + opt-level = 'z' 437k

開啟LTO

LTO(Link Time Optimization)可以在鏈接時消除冗余代碼,減小二進制體積——代價是更長的鏈接時間。

Cargo.toml [profile.release] opt-level = 'z' lto = true

優化后前后體積變化

編譯選項 體積
strip 495k
strip + opt-level = 'z' 437k
strip + opt-level = 'z' + lto 436k

優化效果非常不明顯,聊勝于無。

Panic立刻終止

rust默認的panic會在崩潰時進行?;厮荩奖愣ㄎ粏栴}。然而會帶來額外的體積增加,將這一功能使用abort替代。

[profile.release] opt-level = 'z' lto = true panic = 'abort'

優化后前后體積變化

編譯選項 體積
strip 495k
strip + opt-level = 'z' 437k
strip + opt-level = 'z' + lto 436k
strip + opt-level = 'z' + lto + panic = 'abort' 366K

到目前為止,常規的優化手段已經用完了,后續優化需要配合一些代碼的額外變動。

使用rust分析工具bloat對產物進行分析,結果如下:

File .text Size Crate 4.1% 69.0% 192.7KiB std 1.0% 16.8% 46.9KiB jdmp 0.5% 8.1% 22.7KiB [Unknown] 0.2% 3.8% 10.5KiB jni 0.0% 0.5% 1.5KiB cesu8 0.0% 0.4% 1.1KiB adler32 0.0% 0.3% 904B bytes 0.0% 0.2% 640B aho_corasick 0.0% 0.2% 588B regex_syntax 0.0% 0.2% 572B regex_automata 0.0% 0.2% 440B log 0.0% 0.1% 304B memchr 0.0% 0.0% 52B combine 0.0% 0.0% 8B jni_sys

讓我感到驚訝的是我的核心代碼jdmp模塊只占了46.9k,為此要額外引入幾百k的額外開銷!

移除一些無用字符串

在引入的第三方依賴里,開發者自己添加了很多字符串信息,大部分是用來完善提供運行時報錯信息。通過修改、精簡這些依賴庫,刪除無用代碼,又可以省出一部分空間來。

同時,上面的優化盡管使用abort替代了panic,rust編譯器仍然會生出一些格式化的字符串,使用panic_immediate_abort這個編譯選項禁用這個行為。

.cargo/config.toml [unstable] build-std-features = ["panic_immediate_abort"] build-std = ["std","panic_abort"]

優化后前后體積變化

編譯選項 體積
strip 495k
strip + opt-level = 'z' 437k
strip + opt-level = 'z' + lto 436k
strip + opt-level = 'z' + lto + panic = 'abort' + 代碼裁減 + panic_immediate_abort 135k

再次分析,整個文件的體積已經降到了135k,自己開發的核心代碼占總代碼量的52%,基本符合預期。

File .text Size Crate 14.2% 52.0% 41.3KiB jdmp 3.2% 11.7% 9.3KiB core 3.1% 11.4% 9.1KiB jni 3.0% 11.0% 8.8KiB [Unknown] 1.9% 6.8% 5.4KiB std 0.9% 3.3% 2.6KiB alloc 0.3% 1.1% 936B cesu8 0.3% 1.0% 792B adler32 0.1% 0.5% 372B aho_corasick 0.1% 0.4% 316B regex_automata 0.1% 0.3% 220B log 0.1% 0.3% 216B hashbrown 0.0% 0.1% 108B bytes 0.0% 0.1% 44B combine 0.0% 0.1% 44B rustc_demangle 0.0% 0.0% 8B compiler_builtins 0.0% 0.0% 8B jni_sys

優化linker script

盡管目前文件體積已經相比一開始優化了不少,但是還沒有達到接入要求。通過readelf進一步分析ELF文件的各個section,我找到了一些額外的優化空間。

$ aarch64-linux-gnu-readelf -S target/aarch64-linux-android/release/libjdmp.so There are 24 section headers, starting at offset 0x21738: Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .note.android.ide NOTE 0000000000000270 00000270 0000000000000098 0000000000000000 A 0 0 4 [ 2] .dynsym DYNSYM 0000000000000308 00000308 00000000000002e8 0000000000000018 A 7 1 8 [ 3] .gnu.version VERSYM 00000000000005f0 000005f0 000000000000003e 0000000000000002 A 2 0 2 [ 4] .gnu.version_r VERNEED 0000000000000630 00000630 0000000000000040 0000000000000000 A 7 2 4 [ 5] .gnu.hash GNU_HASH 0000000000000670 00000670 0000000000000024 0000000000000000 A 2 0 8 [ 6] .hash HASH 0000000000000694 00000694 0000000000000100 0000000000000004 A 2 0 4 [ 7] .dynstr STRTAB 0000000000000794 00000794 000000000000014d 0000000000000000 A 0 0 1 [ 8] .rela.dyn RELA 00000000000008e8 000008e8 00000000000007f8 0000000000000018 A 2 0 8 [ 9] .rela.plt RELA 00000000000010e0 000010e0 00000000000002a0 0000000000000018 AI 2 19 8 [10] .rodata PROGBITS 0000000000001380 00001380 0000000000001d83 0000000000000000 AM 0 0 8 [11] .eh_frame_hdr PROGBITS 0000000000003104 00003104 0000000000002494 0000000000000000 A 0 0 4 [12] .eh_frame PROGBITS 0000000000005598 00005598 00000000000078cc 0000000000000000 A 0 0 8 [13] .text PROGBITS 000000000000de64 0000ce64 0000000000013e0c 0000000000000000 AX 0 0 4 [14] .plt PROGBITS 0000000000021c70 00020c70 00000000000001e0 0000000000000000 AX 0 0 16 [15] .data.rel.ro PROGBITS 0000000000022e50 00020e50 0000000000000430 0000000000000000 WA 0 0 8 [16] .fini_array FINI_ARRAY 0000000000023280 00021280 0000000000000010 0000000000000008 WA 0 0 8 [17] .dynamic DYNAMIC 0000000000023290 00021290 0000000000000180 0000000000000010 WA 7 0 8 [18] .got PROGBITS 0000000000023410 00021410 0000000000000048 0000000000000000 WA 0 0 8 [19] .got.plt PROGBITS 0000000000023458 00021458 00000000000000f8 0000000000000000 WA 0 0 8 [20] .data PROGBITS 0000000000024550 00021550 0000000000000060 0000000000000000 WA 0 0 8 [21] .bss NOBITS 00000000000245b0 000215b0 0000000000000101 0000000000000000 WA 0 0 8 [22] .comment PROGBITS 0000000000000000 000215b0 00000000000000b2 0000000000000001 MS 0 0 1 [23] .shstrtab STRTAB 0000000000000000 00021662 00000000000000d3 0000000000000000 0 0 1

在對這些section進行優化時,有必要搞清楚每個section在程序運行的作用。

section 作用
.text 代碼段
.data .rodata .bss 數據段
.plt .got .dynamic .dynsym .rela.dyn .rela.plt .shstrtab 運行時被動態鏈接庫解析,用于動態鏈接。
.eh_frame .eh_frame_hdr 用于保存函數的棧幀偏移,方便?;厮?/td>
.gnu.hash .gnu.version .gnu.version_r .hash 保存編譯文件元信息

程序在正常運行時,代碼段、數據段必不可少,同時需要保留動態鏈接需要的section。剩余的section可以移除,可以進一步優化文件體積。值得注意到是,刪除.eh_frame .eh_frame_hdr后,在程序崩潰時只能得到一個崩潰地址,無法進行棧回溯。

創建一個linker script,只保留程序運行最小依賴的section。

PHDRS { headers PT_PHDR PHDRS ; text PT_LOAD FILEHDR PHDRS ; data PT_LOAD ; dynamic PT_DYNAMIC ; } ENTRY(Reset); EXTERN(RESET_VECTOR); SECTIONS { . = SIZEOF_HEADERS; .text : { *(.text .text.*) } :text .rodata : { *(.rodata .rodata.*) } :text . = . + 0x1000; .data : { *(.data .data.*) *(.fini_array .fini_array.*) *(.got .got.*) *(.got.plt .got.plt.*) } : data .bss : {*(.bss .bss.*)} : data .dynamic : { *(.dynamic .dynamic.*) } :data :dynamic /DISCARD/ : { *(.ARM.exidx .ARM.exidx.*); *(.gnu.version .gnu.version.*); *(.gnu.version_r .gnu.version_r.*); *(.eh_frame_hdr .eh_frame .eh_frame_hdr.* .eh_frame.* ); *(.note.android.ident .note.android.ident.*); *(.comment .comment.*); } }

修改編譯參數,替換默認的linker script

.cargo/config.toml [build] target = ["aarch64-linux-android","armv7-linux-androideabi"] [unstable] build-std-features = ["panic_immediate_abort"] build-std = ["std","panic_abort"] [target.aarch64-linux-android] rustflags = ["-C", "link-arg=-Tlinker.lds"] [target.armv7-linux-androideabi] rustflags = ["-C", "link-arg=-Tlinker.lds"]

經過一番操作,程序的體積最終裁減到了95k!完美符合要求。

總結

編譯選項 體積
strip 495k
strip + opt-level = 'z' 437k
strip + opt-level = 'z' + lto 436k
strip + opt-level = 'z' + lto + panic = 'abort' + 代碼裁減 + panic_immediate_abort 135k
strip + opt-level = 'z' + lto + panic = 'abort' + 代碼裁減 + panic_immediate_abort + 移除section 95k


審核編輯 黃宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 安卓
    +關注

    關注

    5

    文章

    2134

    瀏覽量

    57367
  • 動態鏈接庫
    +關注

    關注

    0

    文章

    11

    瀏覽量

    7072
收藏 人收藏

    評論

    相關推薦

    Linux動態鏈接庫的基本概念

    學習Linux動態鏈接庫是一個繞不開的話題,我們今天就一起來看一下什么是動態鏈接庫、動態鏈接庫
    發表于 09-27 14:31 ?1568次閱讀

    關于使用動態鏈接庫及圖像采集的問題

    我用的是方誠科技的工業相機,里面提供了一些動態鏈接庫,包括了相機初始化,采集圖像,顏色處理等函數,我以前都是用VB做的,買相機的時候他會提供VB的模塊,所以用VB比較方便?,F在我想用LABVIEW做
    發表于 05-26 18:05

    什么是動態鏈接庫?如何編寫、生成DLL

    什么是動態鏈接庫?如何編寫、生成DLL
    發表于 01-17 09:54

    關于labview'的動態鏈接庫的問題

    最近使用labview調用動態鏈接庫,使用vs2017生成dll文件,然后調用,但是為什么輸入數組的情況下輸出一直為0呢,我使用公式節點調用同樣的c語言,就沒問題?請教大佬們怎么解決?還有我想問一下labview是調用公式節點的
    發表于 03-14 11:26

    8168的demos里如何加.so的動態鏈接庫

    8168的demos里如何加c++文件生成的 .so的動態鏈接庫
    發表于 06-21 11:56

    基于動態鏈接庫技術的感應器非線性特性校正

    提出一種基于動態鏈接庫技術的傳感器非線性特性校正新方法。將傳感器是數據采集程序與傳感器的非線性特性校正算法置于同一個動態鏈接庫中,這樣應用程序從動態
    發表于 06-25 09:55 ?26次下載

    C++中動態鏈接庫的創建和調用

    動態連接的創建步驟: 一、創建Non-MFC DLL動態鏈接庫 1、打開File —> New —> Project選項,選擇Win32 Dynamic-Link Library
    發表于 11-24 18:13 ?7次下載

    LINUX環境下CLIPS動態鏈接庫的實現方法

    在LINUX環境下,為了簡便、快捷地制作出CLIPS動態鏈接庫,本文采用了CNU AUTOTOOLS把CLIPS嵌入式高級語言編譯成動態鏈接庫的實現方法,重點研究如何編寫配置信息,利用
    發表于 04-14 21:18 ?30次下載

    虛擬儀器中動態鏈接庫的應用

    本文在闡述了動態鏈接庫技術和虛擬儀器中的 動態鏈接 機制的基礎上,詳述了基于DLL的USB接口虛擬儀器的設計的關鍵內容。
    發表于 07-05 17:17 ?27次下載
    虛擬儀器中<b class='flag-5'>動態</b><b class='flag-5'>鏈接庫</b>的應用

    VC++動態鏈接庫編程深入淺出

    靜態鏈接庫動態鏈接庫都是共享代碼的方式,如果采用靜態鏈接庫,則無論你愿不愿意,lib中的指令都被直接包含在最終生成的EXE文件中了。但是若
    發表于 10-21 17:03 ?0次下載
    VC++<b class='flag-5'>動態</b><b class='flag-5'>鏈接庫</b>編程深入淺出

    由MATLAB的.m文件生成動態鏈接庫的方法說明

    由MATLAB的.m文件生成動態鏈接庫的方法說明
    發表于 08-16 18:54 ?0次下載

    英創信息技術WinCE設備動態鏈接庫的制作與調用

    在使用英創ARM9系列主板做開發時,用戶可能希望將自己一部分代碼封裝起來,隱藏代碼的實現過程,只提供接口供其他程序調用。使用動態鏈接庫(Dynamic Link Library)可以很好實現這個要求
    的頭像 發表于 01-15 14:33 ?1167次閱讀
    英創信息技術WinCE設備<b class='flag-5'>動態</b><b class='flag-5'>鏈接庫</b>的制作與調用

    單片機高階技能之動態鏈接庫技術實現

    單片機高階技能之動態鏈接庫技術實現
    發表于 11-17 12:21 ?13次下載
    單片機高階技能之<b class='flag-5'>動態</b><b class='flag-5'>鏈接庫</b>技術實現

    Linux下的靜態鏈接庫動態鏈接庫的區別是什么?

    學習Linux動態鏈接庫是一個繞不開的話題,我們今天就一起來看一下什么是動態鏈接庫動態鏈接庫
    的頭像 發表于 02-17 10:49 ?1310次閱讀
    Linux下的靜態<b class='flag-5'>鏈接庫</b>和<b class='flag-5'>動態</b><b class='flag-5'>鏈接庫</b>的區別是什么?

    深入探討Linux系統中的動態鏈接庫機制

    異?;虮罎?。為深入理解動態鏈接機制及其工作原理,我重溫了《程序員的自我修養》,并通過實踐演示與反匯編分析,了解了動態鏈接的過程。 本文將深入
    的頭像 發表于 12-18 10:06 ?160次閱讀
    深入探討Linux系統中的<b class='flag-5'>動態</b><b class='flag-5'>鏈接庫</b>機制
    主站蜘蛛池模板: 69女poren16| 色偷偷免费| 一丝不遮视频免费观看| 国产精品手机在线| 成人精品视频在线观看播放| 国产精品美女在线| 91精品欧美激情在线播放| 天天做天天爱天天大综合| 久久综合综合久久| 久久久久久青草大香综合精品| 久碰香蕉精品视频在线观看| 国产稀缺精品盗摄盗拍| 欧美日韩色图| 四虎影视网址| 日本免费的一级绿象| 美女被猛男躁免费视频网站| 国产日韩精品一区二区三区| 免费番茄社区性色大片| 黄色网一级片| 久久精品2020| 成人看片免费无限观看视频| 新版天堂中文资源8在线| jiuma和我啪啪| 天天干夜夜欢| 757一本到午夜宫| 亚洲第一区视频| 视频在线一区| 亚洲最大色网站| 人人看人人玩| 国产激情在线观看| 色综合天天操| 好紧好爽的午夜寂寞视频| 国产亚洲精品免费| 三级黄色免费| 日本黄色激情视频| 国产卡一卡2卡三卡免费视频| 天天射天天干天天舔| 亚洲娇小性色xxxx| 一级毛片视频在线| 美女视频黄a| 午夜影院在线观看|