0xBenchmark中垃圾回收测试模块的分析及改进
1. 0xBenchmark介紹
0xBenchmark是google官方的測試程序,0xlab給0xBenchmark集成了17個(gè)benchmark,包括2個(gè)計(jì)算性能,1個(gè)JavaScript基準(zhǔn)測試,7個(gè)2D圖形渲染,4個(gè)3D圖形渲染,1個(gè)垃圾回收性能測試,2個(gè)本地benchmark用來測試系統(tǒng)性能。測試結(jié)果 供詳細(xì)精確的數(shù)據(jù),可以為性能優(yōu)化供指導(dǎo)和比對。它包含的測試項(xiàng)目如下。
計(jì)算性能
- Linpack 測試Java的浮點(diǎn)性能
- Scimark2 測試常用數(shù)學(xué)運(yùn)算性能如快速Fourier變換、矩陣運(yùn)算等性能
JavaScript
- SunSpider JavaScript基準(zhǔn)測試
2D圖形渲染
- Canvas Redraw 測試Canvas繪圖性能
- Draw Circle 一個(gè)簡單的2D動畫程序,測試刷新率
- DrawRect 在畫布上隨機(jī)添加矩形
- DrawCircle2 在畫布上隨機(jī)渲染圓圈
- DrawArc 簡單的2D動畫
- DrawText 計(jì)算文本渲染速度
- DrawImage 計(jì)算圖片渲染速度
3D圖形渲染
- GL Cube 用OpenGL ES去渲染一個(gè)旋轉(zhuǎn)的魔方
- GL Teapot 用OpenGL ES去渲染一個(gè)旋轉(zhuǎn)的茶壺模型
- NeHe Lesson08 測試貼圖著色混合性能
- NeHe Lesson16 測試霧化效果性能
垃圾回收性能
- Garbage Collection 測試?yán)厥招阅?/li>
本地測試程序
- LibMicro 測試系統(tǒng)調(diào)用和庫調(diào)用的性能
- BYTE UnixBench 為Unix類的系統(tǒng)提供了一些基本的性能指標(biāo)
2. 詳解垃圾回收測試模塊
垃圾回收機(jī)制,最早出現(xiàn)于世界上第二元老語言Lisp,Jean E. Sammet曾經(jīng)說過,Lisp語言最長久的共享之一是一個(gè)非語言特征,即代表了系統(tǒng)自動處理內(nèi)存的方法的術(shù)語及其技術(shù)----垃圾收集(GC,Garbage Collection)。
0xBenchmark中就有專門測試android虛擬機(jī)的垃圾回收性能的模塊。此測試程序的代碼移植于由John Ellis和Pete Kovac寫的一個(gè)基準(zhǔn)測試程序。測試的算法是遞歸自頂向下和遞歸自底向上創(chuàng)建完全二叉樹,以及創(chuàng)建大的浮點(diǎn)數(shù)組,對于內(nèi)存塊的創(chuàng)建還分為長生命周期對象和臨時(shí)對象,長生命周期對象的引用要在測試函數(shù)運(yùn)行完畢時(shí)才會丟失,而臨時(shí)對象在創(chuàng)建完畢后即被丟失,測試的基準(zhǔn)為創(chuàng)建對象所需要的時(shí)間。
每個(gè)二叉樹節(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)如下:
class Node {Node left, right;int i, j;Node(Node l, Node r) { left = l; right = r; }Node() { } }遞歸自頂向下創(chuàng)建完全二叉樹的代碼如下:
static void Populate(int iDepth, Node thisNode) {if (iDepth<=0) {//遞歸結(jié)束條件return;} else {iDepth--;//樹深度減一thisNode.left = new Node();thisNode.right = new Node();Populate (iDepth, thisNode.left);//遞歸創(chuàng)建左子樹Populate (iDepth, thisNode.right);//遞歸創(chuàng)建右子樹} }遞歸自底向上創(chuàng)建完全二叉樹的代碼如下:
static Node MakeTree(int iDepth) {if (iDepth<=0) {//遞歸結(jié)束條件return new Node();} else {return new Node(MakeTree(iDepth-1),//自底向上遞歸調(diào)用MakeTree(iDepth-1));} }在測試程序一開始運(yùn)行的時(shí)候就創(chuàng)建長生命周期對象,并在測試結(jié)束前檢查長生命周期的對象是否被回收了,如果回收了則測試失敗。并且長生命周期對象分為兩類,第一類是完全二叉樹,第二類是浮點(diǎn)數(shù)組。
longLivedTree = new Node(); Populate(kLongLivedTreeDepth, longLivedTree);//完全二叉樹double array[] = new double[kArraySize];//浮點(diǎn)數(shù)組 for (int i = 0; i < kArraySize/2; ++i) {//把數(shù)組的一半初始化array[i] = 1.0/i; } .... if (longLivedTree == null || array[1000] != 1.0/1000)update("Failed");//測試結(jié)束,檢查是否還存活。測試程序最主要的測試部分是遞歸創(chuàng)建不同深度的完全二叉樹,同一深度又有自頂向下和自底向上兩種,同時(shí)需要記錄創(chuàng)建完成所需的時(shí)間:
static void TimeConstruction(int depth) {....tStart = System.currentTimeMillis();//記錄開始創(chuàng)建時(shí)間for (int i = 0; i < iNumIters; ++i) {tempTree = new Node();Populate(depth, tempTree);//自頂向下創(chuàng)建完全二叉樹tempTree = null;}tFinish = System.currentTimeMillis();//記錄完成時(shí)間....tStart = System.currentTimeMillis();for (int i = 0; i < iNumIters; ++i) {tempTree = MakeTree(depth);//自底向上創(chuàng)建完全二叉樹tempTree = null;}tFinish = System.currentTimeMillis();.... }上面測試程序中,二叉樹的創(chuàng)建深度以及數(shù)組的大小由以下常數(shù)決定:
public static final int kStretchTreeDepth = 16; // about 8Mb public static final int kLongLivedTreeDepth = 14; // about 2Mb public static final int kArraySize = 125000; // about 2Mb public static final int kMinTreeDepth = 2; public static final int kMaxTreeDepth = 8;可以看到無論是二叉樹的深度還是浮點(diǎn)數(shù)組的大小,對象系統(tǒng)內(nèi)存的占用都不是很大,這是因?yàn)橐郧癮ndroid設(shè)備的硬件配置都比較低,內(nèi)存也比較少,而現(xiàn)在android設(shè)備的硬件配置普遍比較高,無論是CPU主頻還是內(nèi)存容量都有了很大的提高。導(dǎo)致的結(jié)果就是現(xiàn)在android設(shè)備運(yùn)行這個(gè)benchmark測出來的垃圾回收性能的差異很難觀察到。這也是本文想對此benchmark進(jìn)行改進(jìn)的原因,改進(jìn)后使其能測試當(dāng)前主流android設(shè)備的垃圾回收性能。
3. 改進(jìn)及測試結(jié)果分析
根據(jù)上節(jié)分析,準(zhǔn)備根據(jù)真實(shí)硬件的配置相應(yīng)修改二叉樹的創(chuàng)建深度以及數(shù)組的大小,并在android設(shè)備上測試。選用的開發(fā)板是Tiny4412,是Samsung ARM Cortex-A9四核Exynos4412 Quad-core處理器,運(yùn)行主頻是1.5GHz,內(nèi)存是DDR3 RAM,大小為1G。運(yùn)行的android版本是5.0.2,由于android5.0中得ART GC不會把所有GC log都打印出來,為了更加準(zhǔn)確的獲知GC的運(yùn)行情況,需要修改android源碼,屏蔽過濾GC log的語句,重新編譯并生成libart.so。
未經(jīng)修改的0xBenchmark的垃圾回收性能測試結(jié)果如下:
程序測試過程中內(nèi)存的變化情況如下所示:
測試過程中共發(fā)生15次GC:
由上面的測試結(jié)果可以看出,由于原始的測試程序設(shè)置的二叉樹深度和數(shù)組的大小都相對較小,所以測試所需求的內(nèi)存也比較少,基本都在8M左右,完成整個(gè)垃圾回收測試所需要的時(shí)間只有847ms,其中GC只觸發(fā)了15次。
為了使0xBenchmark能更好的適配現(xiàn)在主流的android硬件設(shè)備,能更加好的使測試結(jié)果能表征android虛擬機(jī)的垃圾回收性能,調(diào)整二叉樹的創(chuàng)建深度及數(shù)組大小如下:
public static final int kStretchTreeDepth = 19; public static final int kLongLivedTreeDepth = 18; public static final int kArraySize = 125000*8; public static final int kMinTreeDepth = 2; public static final int kMaxTreeDepth = 12;經(jīng)過改進(jìn)后的垃圾回收測試結(jié)果如下:
測試過程中內(nèi)存的變化情況如下所示:
測試過程中共發(fā)生86次GC,部分截圖如下:
可以看到,完成整個(gè)測試所需的時(shí)間變?yōu)榱?162ms,在測試過程中也發(fā)成了較多的GC,共86次,更加能夠表征GC對于對象分配的影響,同時(shí),測試過程中java堆的大小在32M左右,由android啟動參數(shù)dalvik.vm.heapgrowthlimit=64m可知,每個(gè)app的堆得增長上限是64M,測試程序更好的模擬了正常應(yīng)用的內(nèi)存消耗行為。
原文地址:?http://hello2mao.github.io/2015/11/30/0xBenchmark.html
總結(jié)
以上是生活随笔為你收集整理的0xBenchmark中垃圾回收测试模块的分析及改进的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android ART GC之GrowF
- 下一篇: 详解Linux-I2C驱动