1. 程式人生 > >Android 系統性能優化(52)---移動端效能監控方案Hertz

Android 系統性能優化(52)---移動端效能監控方案Hertz

效能問題是造成App使用者流失的罪魁禍首之一。App的效能問題包括崩潰、網路請求錯誤或超時、響應速度慢、列表滾動卡頓、流量大、耗電等等。而導致App效能低下的原因有很多,除去裝置硬體和軟體的外部因素,其中大部分是開發者錯誤地使用執行緒、鎖、系統函式、程式設計正規化、資料結構等導致的。即便是最有經驗的程式設計師,也很難在開發時就能避免所有導致效能低下的“坑”,因此解決效能問題的關鍵是在於能不能儘早地發現和定位這些“坑”。

美團外賣在實踐中通過總結常見效能問題,並在學習了業內微信、360等效能監控技術原理後,開發了一套移動端效能監控解決方案——Hertz(赫茲)。Hertz的目標是實現這三個功能:

  • 開發時期,檢查效能異常點並通知給開發者;
  • 測試時期,和現有測試工具結合產生效能測試報告;
  • 上線時期,通過監控平臺上報效能資料,實現線上問題定位和追查。

要實現這三個功能,首先要採集到可衡量、有價值的效能資料,因此效能資料的採集是我們關注的最核心的問題之一。

資料採集

雖然使用者可以感知到的效能問題多種多樣,我們仍然可以將其抽象成具體的監控指標。在Hertz中這些監控指標包括:FPS、CPU使用率、記憶體佔用、卡頓、頁面載入時間、網路請求流量 等。這其中有的效能指標比較容易獲取,例如FPS、CPU使用率、記憶體佔用等,有的效能指標不易獲取,例如卡頓、頁面載入時間、網路請求流量等。

例如在iOS中我們可以這樣獲取FPS:

- (void)tick:(CADisplayLink *)link
{
    NSTimeInterval deltaTime = link.timestamp - self.lastTime;
    self.currentFPS = 1 / deltaTime;
    self.lastTime = link.timestamp;
}

在Android中我們可以這樣獲取記憶體佔用:

public long useSize() {
    Runtime runtime = Runtime.getRuntime();
    long totalSize = runtime.maxMemory() >> 10;
    this.memoryUsage = (runtime.totalMemory() - runtime.freeMemory()) >> 10;
    this.memoryUsageRate = this.memoryUsage * 100 / totalSize;
}

上面的例子只是為了說明獲取FPS、記憶體、CPU這些指標非常簡單,但是這些指標必須與其它資料結合才具有意義,這些資料包括當前頁面的資訊、當前App執行時間,或者卡頓發生時程式執行的堆疊和執行日誌

等等。例如:CPU和當前頁面資訊結合,可以評測每個頁面的運算複雜度;記憶體和App執行時間結合,可以觀察記憶體和使用時長的關係進而分析是否發生記憶體洩漏;FPS和卡頓資訊結合,可以評估這次卡頓發生時App的效能究竟下降到什麼程度。

流量消耗

移動端使用者對於流量非常敏感,美團外賣偶爾會收到使用者投訴說短時間內消耗了巨大流量的問題,因此我們思考能不能在App本地統計使用者的流量消耗,並且上報給後臺。這個統計不必精確到每個API,能夠粗略地歸類計算出總的流量消耗即可。我們對於流量統計的維度是:自然日+請求來源+網路型別。為什麼有了服務端流量監控(例如CAT),還需要在客戶端本地監控流量呢?本地流量能夠統計由使用者端發出的全部網路請求,而這點服務端監控是很難做到的。一個例子是並非所有的網路請求都會上報服務端監控;另一個例子是由於網路原因可能造成使用者僅僅消耗了上行流量,但這些請求並沒有到服務端。

在iOS中我們通過註冊NSURLProtocol實現流量統計:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [self.client URLProtocolDidFinishLoading:self];

    self.data = nil;
    if (connection.originalRequest) {
        WMNetworkUsageDataInfo *info = [[WMNetworkUsageDataInfo alloc] init];
        self.connectionEndTime = [[NSDate date] timeIntervalSince1970];
        info.responseSize = self.responseDataLength;
        info.requestSize = connection.originalRequest.HTTPBody.length;
        info.contentType = [WMNetworkUsageURLProtocol getContentTypeByURL:connection.originalRequest.URL andMIMEType:self.MIMEType];
    [[WMNetworkMeter sharedInstance] setLastDataInfo:info];
    [[WMNetworkUsageManager sharedManager] recordNetworkUsageDataInfo:info];
}

}

在Android中我們通過基於Aspectj的AOP方式攔截網路請求API實現流量統計:

@Pointcut("target(java.net.URLConnection) && " +
        "!within(retrofit.appengine.UrlFetchClient) " +
        "&& !within(okio.Okio) && !within(butterknife.internal.ButterKnifeProcessor) " +
        "&& !within(com.flurry.sdk.hb)" +
        "&& !within(rx.internal.util.unsafe.*) " +
        "&& !within(net.sf.cglib..*)" +
        "&& !within(com.huawei.android..*)" +
        "&& !within(com.sankuai.android.nettraffic..*)" +
        "&& !within(roboguice..*)" +
        "&& !within(com.alipay.sdk..*)")
protected void baseCondition() {

}

@Pointcut("call (org.apache.http.HttpResponse org.apache.http.client.HttpClient.execute(org.apache.http.client.methods.HttpUriRequest))"
        + "&& target(org.apache.http.client.HttpClient)"
        + "&& args(request)"
        + "&& !within(com.sankuai.android.nettraffic.factory..*)"
        + "&& baseClientCondition()"
)
void httpClientExecute(HttpUriRequest request) {

}

統計到總的流量消耗後,我們還希望對流量進行粗略的歸類,方便定位問題。有兩個因素是我們關心的:第一是請求來源,即流量消耗是來自API請求,H5還是CDN的;第二是網路型別,即Wifi、4G還是3G流量。對於流量來源,我們首先通過域名做下簡單的歸類。以iOS為例,示例程式碼如下:

- (NSString *) regApiHost {
    return _regApiHost ? _regApiHost :@"^(.*\\.)?(meituan\\.com|maoyan\\.com|dianping\\.com|kuxun\\.cn)$";
}

- (NSString *) regResHost {
    return _regResHost ? _regResHost : @"^(.*\\.)?(meituan\\.net|dpfile\\.com)$";
}

- (NSString *) regWebHost {
    return _regWebHost ? _regWebHost : @"^(.*\\.)?(meituan\\.com|maoyan\\.com|dianping\\.com|kuxun\\.cn|meituan\\.net|dpfile\\.com)$";
}

但是某些域名可能既部署了API服務,又部署了Web服務。對於這類域名,我們還通過校驗返回包的MIMEType作進一步的區分。以iOS為例,示例程式碼如下:

+ (BOOL)isPermissiveWebURL:(NSURL *)URL andMIMEType:(NSString *)MIMEType
{
    NSRegularExpression *permissiveHost = [NSRegularExpression regularExpressionWithPattern:[[WMNetworkMeter sharedInstance] regWebHost]
                                                                                options:NSRegularExpressionCaseInsensitive
                                                                                  error:nil];
    NSString *host = URL.host;
    return ([MIMEType isEqualToString:@"text/css"] || [MIMEType isEqualToString:@"text/html"] || [MIMEType isEqualToString:@"application/x-javascript"] || [MIMEType isEqualToString:@"application/javascript"]) && (host && [permissiveHost numberOfMatchesInString:host options:0 range:NSMakeRange(0, [host length])]);
}

頁面載入時間

要測量頁面載入時間,我們要解決兩個問題。第一,如何衡量一個頁面的載入時間;第二,如何儘量不寫或少寫程式碼來實現測速。先看第一個問題,以Android為例,在Activity的建立載入過程中,會執行很多操作,例如設定頁面主題,初始化頁面佈局,載入圖片,獲取網路資料或讀寫資料庫等等。上述操作的任何一個環節出現效能問題都可能導致畫面不能及時顯示,影響使用者體驗。Hertz將這些可能發生的操作抽象為下圖所示的測速模型:

其中T1指頁面初始化到第一個UI元素顯示的時間,這個UI元素一般是指資料載入時的等待動畫之類的。T2是指網路請求時間,這個時間的開始點有可能早於T1的結束點。T3是載入到資料後,為UI填充資料並重新渲染完成的時間。T是整個頁面從初始化到最終UI繪製完成的時間。

對於第二個問題,如果每個時間點都需要人工寫程式碼埋點的話,效率非常低並且容易出錯。因此,Hertz通過一個配置檔案配置每個頁面對應的API,在API請求的基類中統一埋點。這個方案當然還有優化空間,例如hook關鍵節點上的API呼叫注入埋點程式碼。

[{
  "page": "MainActivity",
  "api": [
    "/poi/filter",
    "/home/head",
    "/home/rcmdboard"
  ]
},
{
  "page": "RestaurantActivity",
  "api": [
    "/poi/food"
  ]
}]

此外,還有一個問題是如何判定UI渲染完成?在Android中,Hertz的做法是在Activity的rootView中插入一個FrameLayout,並且監聽這個FrameLayout是否呼叫了dispatchDraw方法實現的。當然,這個方案的缺點是由於插入了一級View導致層級巢狀變深。

@Override
protected void dispatchDraw(Canvas canvas) {
    super.dispatchDraw(canvas);
    if (!mIsComplete) {
        mIsComplete = mCallback.onDrawEnd(this, mKey);
    }
}

在iOS中我們採取了不同的做法,Hertz在配置檔案中指定最終渲染頁面的某個元素的tag,並在網路請求成功後開啟CADisplayLink檢查該元素是否出現在根節點下面。

- (void)tick:(CADisplayLink *)link
{
    [_currentTrackRecordArray enumerateObjectsUsingBlock:^(WMHertzPageTrackRecord * _Nonnull record, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([self findTag:record.configItem.tag inViewHierarchy:record.rootView]) {
            [self endPageRenderEvent:record];
        }
    }];
}

卡頓

目前主流移動裝置均採用雙快取+垂直同步的顯示技術。大概原理是顯示系統有兩個緩衝區,GPU會預先渲染好一幀放入一個緩衝區內,讓視訊控制器讀取,當下一幀渲染好後,GPU會直接將視訊控制器的指標指向第二個容器。這裡,GPU會等待顯示器的VSync(即垂直同步)訊號發出後,才進行新的一幀渲染和緩衝區更新。

大多數手機的螢幕重新整理頻率是60HZ,如果在 1000/60=16.67ms 內沒有將這一幀的任務執行完畢,就會發生丟幀現象,這便是使用者感受到卡頓的原因。這一幀的繪製任務包括CPU的工作和GPU的工作兩部分,CPU負責計算顯示的內容,例如檢視建立、佈局計算、圖片解碼、文字繪製等等,隨後CPU將計算好的內容提交給GPU,由GPU進行變換、合成、渲染。

除了UI繪製外,系統事件、輸入事件、程式回撥服務、以及我們插入的其它程式碼也都在主執行緒中執行,那麼一旦在主執行緒裡添加了操作複雜的程式碼,這些程式碼就有可能阻礙主執行緒去響應點選、滑動事件,以及阻礙主執行緒的UI繪製操作,這就是造成卡頓的最常見原因。

在瞭解了螢幕繪製原理和卡頓形成的原因後,很容易想到通過檢測FPS就可以知道App是否發生了卡頓,也能夠通過一段連續的FPS幀數計算丟幀率來衡量當前頁面繪製的質量。然而實踐發現FPS的重新整理頻率非常快,並且容易發生抖動,因此直接通過比較通過FPS來偵測卡頓是比較困難的。而檢測主執行緒訊息迴圈執行的時間就要容易的多了,這也是業內常用的一種檢測卡頓的方法。因此,Hertz在實踐中採用的就是檢測主執行緒每次執行訊息迴圈的時間,當這一時間大於閾值時,就記為發生一次卡頓。

在實踐中我們發現,有的卡頓連續性耗時較長,例如開啟新頁面時的卡頓;而有的卡頓連續性耗時相對較短但頻次較快,例如列表滑動時的卡頓。因此,我們採用了“N次卡頓超過閾值T”的判定策略,即一個時間段內卡頓的次數累計大於N時才觸發採集和上報:例如卡頓閾值T=2000ms、卡頓次數N=1,可以判定為單次耗時較長的卡頓;而卡頓閾值T=300ms、卡頓次數N=5,可以判定為頻次較快的卡頓。

Runnable loopRunnable = new Runnable() {
    @Override
    public void run() {
        if (mStartedDetecting && !isCatched) {
            nowLaggyCount++;
            if (nowLaggyCount >= N) {
                blockHandler.onBlockEvent();
                isCatched = true;
                ...
            }
        }
    }
};

public void onMainLoopFinish(){
    if(isCatched){
        blockHandler.onBlockFinishEvent(loopStartTime,loopEndTime);
    }
    resetStatus();
    ...
}

當檢測到卡頓後,如何定位到造成卡頓的問題呢?如果能抓取到卡頓發生時程式的呼叫堆疊和執行日誌,是不是很酷?的確,通過抓取堆疊可以非常有效地幫我們定位到造成卡頓的“問題程式碼”。

在實踐中我們發現抓取堆疊有兩個需要注意的問題。

第一個問題是堆疊抓取的時機。抓取堆疊的時機必須是在卡頓發生當時,而不是之後,否則不能準確抓到造成卡頓的程式碼,因此在子執行緒中當卡頓還沒有結束時,我們就會抓取堆疊。

第二個問題是堆疊如何歸類,卡頓堆疊的歸類和Crash堆疊不同,以最內層程式碼歸類顯然是不合適的,因為外層不同的業務邏輯程式碼在最內層的呼叫堆疊有可能是相同的。以最外層程式碼歸類也是不合適的,因為最外層程式碼有可能是業務邏輯程式碼,也有可能是系統呼叫。

目前Hertz的做法是按照最內層歸類的原則,並匹配一些簡單的規則,以命中規則的類名來歸類。

擴充套件性和易用性

Hertz非常重視SDK的可擴充套件性和易用性,在設計之初我們就做了很多考量。SDK的框架如下圖所示,整體上分為三層:最上層是介面層,提供極少量的對外暴露的方法,以及環境和配置引數等。第二層是業務層,包含了頁面測速、卡頓檢測和引數採集等所有的核心邏輯。第三層是資料適配層,將業務層產生的資料封裝為統一的資料結構,並通過介面卡適配到不同的輸出通道上。

設計上我們第一個考量就是介面的易用性,Hertz內建了三種執行模式:開發模式、測試模式和線上模式。開發者只需要指定一種模式,Hertz就可以開始工作了。各種模式預設了SDK執行所需要的引數,例如取樣頻率、卡頓閾值、上報通道開關等,而監控指標的採集、卡頓的偵測、頁面測速等邏輯都在內部自動執行。以Android為例,示例程式碼如下:

final HertzConfiguration configuration = new HertzConfiguration.Builder(this)
        .mode(HertzMode.HERTZ_MODE_DEBUG)
        .appId(APP_ID)
        .unionId(UNION_ID)
        .build();
Hertz.getInstance().init(configuration);

設計上我們第二個考量是SDK的可擴充套件性。以資料適配層為例,目前內建了五種適配通道,可以將採集到的監控資料適配到不同的資料通道。根據選擇的工作模式不同,資料將被適配到服務端監控通道,生成測試報告,或者只在App本地輸出日誌和提示。這種設計帶來的一個好處是,如果需要新增一種資料輸出通道,既可以在上層新增一個攔截器,也可以只改動SDK極少量的程式碼來新增一個介面卡。同樣的,效能採集模組和頁面測速模組的設計也遵循這種思路。

實際應用

美團外賣在接入Hertz後,初步具備了發現、定位效能問題的能力,在開發期、測試期、線上期都對Hertz進行了實際驗證。

開發期應用

在開發期接入Hertz,相當於集成了一個離線的效能檢測工具,當檢測到異常時,Hertz將這些資料直接反饋給開發者,如下圖所示:

執行時採集的資料會輸出到日誌中,而App的頁面上也會插入一個浮層來展示當前的FPS、CPU、記憶體等基本資訊。如果檢測到卡頓發生,會彈出提示頁面並列出當前的執行堆疊。目前從卡頓檢測結果來看,大部分堆疊日誌可以比較明顯的定位到有問題的程式碼,只要略微檢視程式碼和分析原因,這些問題都能很容易的優化。

下面是初始化複雜UI造成卡頓的例子:

android.content.res.StringBlock.nativeGetString(Native Method)
android.content.res.StringBlock.get(StringBlock.java:82)
android.content.res.XmlBlock$Parser.getName(XmlBlock.java:175)
android.view.LayoutInflater.inflate(LayoutInflater.java:470)
android.view.LayoutInflater.inflate(LayoutInflater.java:420)
android.view.LayoutInflater.inflate(LayoutInflater.java:371)
com.sankuai.meituan.takeoutnew.controller.ui.PoiListAdapterController.getView(PoiListAdapterController.java:77)
com.sankuai.meituan.takeoutnew.adapter.PoiListAdapter.getView(PoiListAdapter.java:26)
android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:220)

下面是使用Gson反向解析字串時造成卡頓的例子:

com.google.gson.Gson.toJson(Gson.java:519)
com.meituan.android.common.locate.util.GoogleJsonWrapper    $MyGson.toJson(GoogleJsonWrapper.java:236)
com.sankuai.meituan.location.collector.CollectorJson    $MyGson.toJson(CollectorJson.java:216)
com.sankuai.meituan.location.collector.CollectorFilter.saveCurrentData(CollectorFilter.java:67)
com.sankuai.meituan.location.collector.CollectorFilter.init(CollectorFilter.java:33)
com.sankuai.meituan.location.collector.CollectorFilter.<init>(CollectorFilter.java:27)
com.sankuai.meituan.location.collector.CollectorMsgHandler.recordGps(CollectorMsgHandler.java:134)
com.sankuai.meituan.location.collector.CollectorMsgHandler.getNewLocation(CollectorMsgHandler.java:81)
com.meituan.android.common.locate.LocatorMsgHandler$1.handleMessage(LocatorMsgHandler.java:29)

下面是主執行緒讀寫資料庫造成卡頓的例子:

android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:782)
android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
de.greenrobot.dao.AbstractDao.executeInsert(AbstractDao.java:306)
de.greenrobot.dao.AbstractDao.insert(AbstractDao.java:276)
com.sankuai.meituan.takeoutnew.db.dao.BaseAbstractDao.insert(BaseAbstractDao.java:25)
com.sankuai.meituan.takeoutnew.log.LogDataUtil.insertIntoDb(LogDataUtil.java:243)
com.sankuai.meituan.takeoutnew.log.LogDataUtil.saveLogInfo(LogDataUtil.java:221)
com.sankuai.meituan.takeoutnew.log.LogDataUtil.saveLog(LogDataUtil.java:116)
com.sankuai.meituan.takeoutnew.log.LogDataUtil.saveLogInfo(LogDataUtil.java:112)
com.sankuai.meituan.takeoutnew.ui.page.main.order.OrderListFragment.onPageShown(OrderListFragment.java:306)
com.sankuai.meituan.takeoutnew.ui.page.main.order.OrderListFragment.init(OrderListFragment.java:151)
com.sankuai.meituan.takeoutnew.ui.page.main.order.OrderListFragment.onCreateView(OrderListFragment.java:81)

從上報的具體問題來看,大部分日誌可以比較明顯的定位到有問題的程式碼,只要略微檢視程式碼和分析原因,這些問題都能很容易優化。

測試期應用

傳統的效能測試大多依賴於第三方工具,產生的資料和開發實測的資料有較大出入,此外,這些測試往往只給出一些指標的資料,而不能幫助開發者定位到問題所在。我們在測試階段使用Hertz採集效能資料,測試手段可以是人工測試,也可以是自動化測試或者monkey測試。得到效能資料後,通過指令碼處理後會發出一個簡單的測試報告。

當然這種形式的測試報告仍然需要手工來匯出日誌和執行指令碼,未來我們會在此基礎上開發一套自動化的測試工具。

上線期應用

對於卡頓檢測,除了在開發期和測試期Hertz能立即將問題反饋給開發者外,在灰度或線上執行時Hertz也會將資料上傳到服務端,目前上報通道是公司內部的CAT(已經開源,詳情請參考深度剖析開源分散式監控CAT一文)。可以看到堆疊的歸類和展示和我們熟悉的Crash監控非常類似,按照前面提到的歸類原則,卡頓堆疊按照發生的次數排列,並且可以按照版本、作業系統、裝置過濾,比較符合開發者的使用習慣。

對於流量的統計,我們每天會上報到服務端全網使用者的流量消耗資料,並輸出一個報表,列出全網流量消耗Top100的使用者。如果發現異常,可以進一步根據後端日誌和客戶端診斷日誌來排查具體是哪個網路請求導致的流量異常。

對於頁面測速資料和FPS、CPU、記憶體等基礎指標,Hertz也會將資料上報到CAT,評測App整體的效能狀況。

總結

效能優化是每一個成熟的App都必須認真對待的話題,而效能優化的痛點往往在於不能及時發現問題,或者發現了問題卻不能定位問題。美團外賣以監控資料指導效能優化的思路,在實踐中開發和完善了App效能監控方案Hertz,並且在效能資料的監控和應用方面做了一些探索和驗證。

目前Hertz的監控指標包括了FPS、CPU使用率、記憶體佔用、卡頓、頁面載入時間、網路請求流量等,而耗電量、App冷啟動,以及Exception等監控後續會逐步加入到Hertz的監控目標中去。效能監控的指標在未來可能會複用多個現有工具,並且在此基礎上逐步完善

Hertz的卡頓偵測和堆疊抓取能夠非常有效地幫助開發者定位效能問題,但是目前的卡頓偵測策略還有很多優化的空間。例如是否可以根據裝置不同設定不同的閾值,以及在App執行的不同時期設定不同的策略。而對於堆疊的歸類,目前的規則只是簡單地匹配類名字首,如何更精準、更合理的分類也是我們未來要更多考慮的問題。當然,這些優化還需要更多的資料樣本做支撐。

建立視覺化的、友好的效能測試工具也同樣非常重要,例如一個可實時檢視,也可翻閱歷史報告的Web頁面。同時,Hertz在設計上可以很容易的和自動化測試手段相結合,或者在整合階段自動生成測試報告,然而在這方面我們才僅僅做了一些初步的嘗試。當我們具備了準確採集效能資料的能力之後,如何更好地應用到包括測試環節在內的整個開發流程中,仍然需要長期的探索和實踐

本文主要介紹美團外賣在Hertz的實踐過程中總結的一些思路和實現手段,而圍繞App效能監控還有很多有趣的,和更深入的主題並沒有涉及。例如如何平衡效能監控工具和工具本身所帶來的效能問題,效能優化的具體技巧和手段,以及對效能資料做進一步分析從而建立起異常裝置的監控體系等等。未來我們也將在這些問題上做進一步探索、實踐和分享。

參考文獻

相關推薦

Android 系統性優化52---移動效能監控方案Hertz

效能問題是造成App使用者流失的罪魁禍首之一。App的效能問題包括崩潰、網路請求錯誤或超時、響應速度慢、列表滾動卡頓、流量大、耗電等等。而導致App效能低下的原因有很多,除去裝置硬體和軟體的外部因素,其中大部分是開發者錯誤地使用執行緒、鎖、系統函式、程式設計正規化、資料結構等導致的。即便是最有經驗的程式設計師

android系統性優化63---Android APP 卡頓問題分析及解決方案

使用者對卡頓的感知, 主要來源於介面的重新整理. 而介面的效能主要是依賴於裝置的UI渲染效能. 如果我們的UI設計過於複雜, 或是實現不夠友好,計算繪製演算法不夠優化, 裝置又不給力, 介面就會像卡住了一樣, 給使用者卡頓的感覺.如果你的應用介面出現卡頓不流暢的情況,不用懷疑,這很大原因是你沒有在16ms完成

Android 系統性優化11---UC效能優化方案

       一、效能優化六項指標:              效能、記憶體、穩定性、流量、電量、安裝包大小;       二、背景 ---- Android程式卡頓產生原因:              1、Android系統低效              --渲染執行緒、同步介面、廣播機制         

Android 系統性優化36---顯示效能指標

    從 Android 誕生的那一刻起,流暢度就為眾人所關注。一時之間,似乎所有人都在討論 Android 和 iOS 誰的流暢度更好。但是,毫不誇張的說,流暢度絕對是 Android 眾多效能維度中最為奇葩的一個。因為,為了刻畫這一效能維度,業界設計了各式各樣的指標來對

Android 系統性優化16--Android 系統性優化第4季

1)Cachematters for networking想要使得Android系統上的網路訪問操作更加的高效就必須做好網路資料的快取。這是提高網路訪問效能最基礎的步驟之一。從手機的快取中直接讀取資料肯定比從網路上獲取資料要更加的便捷高效,特別是對於那些會被頻繁訪問到的資料,

Android 系統性優化34---Android UI 效能優化

Android官網 Slow rendering;個人覺得非常有價值,比如指出 物件分配、垃圾回收(GC)、執行緒排程以及Binder呼叫 是Android系統中常見的卡頓原因,更重要的是給出了定位和解決這些問題的方案;而非簡單地告訴你避免物件分配,減少佈局層級,減少過度

Android系統性優化64---build.設定

1. 強制把Home程式駐入記憶體.引數:ro.HOME_APP_ADJ=12.提高 JPG 質量為 100%引數:ro.media.enc.jpeg.quality=1003. VM 虛擬堆大小; 提高 RAM引數:dalvik.vm.heapsize=48m4. 使用 GPU 渲染UI引數:debug.s

Android 系統性優化28---Android 效能優化工具集合

磁碟檔案讀寫:每次開啟、關閉或者讀寫檔案,作業系統都需要經過從使用者態轉換為核心態的切換,這種狀態的切換本身是很消耗效能的,所以為了提高檔案的讀寫效率,就需要儘量減少使用者態和核心態的切換。使用快取可以避免重複讀寫,對於需要多次訪問的資料,在第一次取出資料的時候,將資料放在快

Android系統性優化44---全面&詳細的記憶體優化指南

前言在 Android開發中,效能優化策略十分重要本文主要講解效能優化中的記憶體優化,希望你們會喜歡目錄1. 定義優化處理 應用程式的記憶體使用、空間佔用2. 作用避免因不正確使用記憶體 & 缺乏管理,從而出現 記憶體洩露(ML)、記憶體溢位(OOM)、記憶體空間佔用

Android 系統性優化30---Android效能全面分析與優化方案研究

5.1、渲染問題先來看看造成應用UI卡頓的常見原因都有哪些?1、人為在UI執行緒中做輕微耗時操作,導致UI執行緒卡頓;2、佈局Layout過於複雜,無法在16ms內完成渲染;3、同一時間動畫執行的次數過多,導致CPU或GPU負載過重;4、View過度繪製,導致某些畫素在同一幀時間內被繪製多次,從而使CPU或G

移動效能監控方案Hertz

效能問題是造成App使用者流失的罪魁禍首之一。App的效能問題包括崩潰、網路請求錯誤或超時、響應速度慢、列表滾動卡頓、流量大、耗電等等。而導致App效能低下的原因有很多,除去裝置硬體和軟體的外部因素,其中大部分是開發者錯誤地使用執行緒、鎖、系統函式、程式設計正規化、資料結構等

前端性優化移動瀏覽器前端優化策略

因此 本地 網絡流量 桌面 cse kit 極致 加載 文件 相對於桌面端瀏覽器,移動端Web瀏覽器上有一些較為明顯的特點:設備屏幕較小、新特性兼容性較好、支持一些較新的HTML5和CSS3特性、需要與Native應用交互等。但移動端瀏覽器可用的CPU計算資源和網絡資源極為

Android繪制優化繪制性分析

pro -i tco public 繼續 但是 們的 sched mda 前言 一個優秀的應用不僅僅是要有吸引人的功能和交互,同時在性能上也有很高的要求。運行Android系統的手機,雖然配置在不斷的提升,但仍舊無法和PC相比,無法做到PC那樣擁有超大的內存以及高性能的CP

Mysql數據庫性優化

效率 dir sort variables 緩存 模型 mysql5.6 包含 dpt 參考 http://www.jb51.net/article/82254.htm 今天,數據庫的操作越來越成為整個應用的性能瓶頸了,這點對於Web應用尤其明顯。關於數據庫的性能,這並不只

Android內存優化DVM和ART原理初探

java虛擬機 劃分 cimage beef 靜態 由於 jar blank 查找 要學習Android的內存優化,首先要了解Java虛擬機,此前我用了多篇文章來介紹Java虛擬機的知識,就是為了這個系列做鋪墊。在Android開發中我們接觸的是與Java虛擬機類似的Dal

mysql性優化

配置文件 mysql 數據庫 網絡 信息 mysql性能優化、慢查詢分析、優化索引和配置一.每項的基本思路步驟1.性能瓶頸定位:show命令、慢查詢日誌、explain分析查詢、profiling分析查詢、2.索引及查詢優化3.配置優化二.my

Web頁面性優化YSlow

java 字符 新版 目標 網絡 imp web頁面 檢查 用戶 YSlow(解析為Why Slow)是雅虎基於網站優化規則推出的工具,幫助你分析並優化網站性能。舊版Yslow 有13條規則,新版Yslow有23項規則,YSlow會根據這些規則分析你的網站,並給出評級。

從-View-繪制談性優化

有趣 || left 例子 bject create 我想 roo 並且 在開發過程中,往往會聽到 “性能優化” 這個概念,這個概念很大,比如網絡性能優化、耗電量優化等等,對我們開發者而言,最容易做的,或者是影響最大的,應該是 View 的性能優化。一般小項目或許用不上

前端性優化:桌面瀏覽器前端優化策略

data lan ucc 靜態 sync 怎樣 拆分 打包成 pan 摘要: 前端性能優化是一個很寬泛的概念,本書前面的部分也多多少少提到一些前端優化方法,這也是我們一直在關註的一件重要事情。配合各種方式、手段、輔助系統,前端優化的最終目的都是提升用戶體驗,改善頁面性能,我

10種簡單的Java性優化

IT none hset 工作流程 執行 為什麽 util 服務器 也有 本文由 ImportNew - 一直在路上 翻譯自 jaxenter。歡迎加入翻譯小組。轉載請見文末要求。你是否正打算優化hashCode()方法?是否想要繞開正則表達