使用 Logcat 寫入與檢視記錄

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

Android Studio 的「Logcat」視窗會顯示系統訊息,如進行垃圾收集,以及您使用 Log 類別加到應用程式內的訊息。此視窗會即時顯示訊息,並保留歷史記錄,讓您可以查看過往訊息。

您可以藉由建立篩選條件、修改訊息顯示的資訊量、設定優先等級、只顯示來自應用程式程式碼的訊息,以及搜尋記錄等方式,讓畫面上只顯示您需要的資訊。logcat 預設只會顯示最近執行的應用程式相關的輸出記錄。

應用程式回傳例外狀況時,logcat 會顯示訊息,然後顯示相關的堆疊追蹤記錄,裡面有該行程式碼的連結。

從 Android Studio 2.2 起,「Run」(執行) 視窗只會顯示目前執行的應用程式記錄訊息。請注意,您可以設定 logcat 的輸出顯示畫面,但是不能設定「Run」(執行) 視窗的顯示畫面。

檢視應用程式記錄

若要顯示應用程式的記錄訊息:

  1. 在裝置上建構並執行應用程式
  2. 按一下「View」(檢視) >「Tool Windows」(工具視窗) >「Logcat」 (或按一下工具視窗列中的「Logcat」)。

Logcat 視窗會顯示透過視窗頂端下拉式選單選擇的應用程式的記錄訊息,如圖 1 所示。

圖 1. Logcat 視窗

logcat 預設只會顯示裝置上執行的應用程式的記錄訊息。若要變更這項預設設定,請參閱如何篩選 logcat 訊息

Logcat 工具列有以下按鈕:

  1. 「Clear logcat」(清除 logcat) :按一下即可清除看到的記錄。
  2. 「Scroll to the end」(捲動至末端) :按一下即可跳到記錄末端,查看最新的記錄訊息。如果您點選記錄內的文字行,檢視畫面會暫停捲動留在該處。
  3. 「Up the stack trace」(堆疊追蹤記錄向上) 及「Down the stack trace」(堆疊追蹤記錄向下) :按一下即可在堆疊追蹤記錄中上下導航,以便在列印的例外狀況中選取後續出現的檔案名稱 (並可在編輯工具中檢視對應的行數編號)。這和您在記錄檔案名稱上按一下的行為相同。
  4. 「Use soft wraps」(使用柔性納入) :點一下即可啟用行納入功能,防止水平捲動 (不過如果有不法分行的字串,還是需要水平捲動)。
  5. 「Print」(列印) :按一下即可列印 logcat 訊息。在出現的對話方塊中選擇列印偏好設定後,您也可以選擇儲存為 PDF。
  6. 「Restart」(重新啟動) :按一下即可清除記錄並重新啟動 logcat。這和「Clear logcat」(清除 logcat) 按鈕不同之處在於,這樣做會復原並顯示之前的記錄訊息,如果 Logcat 開始反應不良,而您又不想喪失記錄訊息時,這個功能就非常有幫助。
  7. 「Logcat header」(Logcat 標頭) :按一下即可開啟「Configure Logcat Header」(設定 Logcat 標頭) 對話方塊,您可以在此自訂每則 logcat 訊息的外觀,例如顯示位置、是否顯示日期時間等等。
  8. 「Screen capture」(螢幕畫面擷取) :按一下即可擷取螢幕截圖
  9. 「Screen record」(螢幕錄影) :按一下即可錄製裝置影片 (最長 3 分鐘)。

寫入記錄訊息

Log 類別可用來建立 logcat 中會顯示的記錄訊息。一般情況下,您應該使用以下記錄方法,以下項目按照重要優先順序排列,由高到低 (或說從最精簡到最詳盡):

更完整的選項清單請參閱 Log 類別說明。

除非還在開發,否則您不應該把詳細記錄編譯到應用程式裡。系統會編譯偵錯記錄進去,但是會在執行階段加以移除,但是會保留錯誤、警示、資訊等幾種記錄。

關於每個記錄方法,第一個參數都應該是專用的標記,第二個參數則是訊息。系統記錄訊息的標記是短字串,說明導致發生此訊息的系統元件 (例如:ActivityManager)。您可以把任何覺得有用的字串設成標記,如目前類別名稱等等。

通常會在類別中宣告 TAG 常數,以便讓第一個參數使用。舉例來說,您可以建立如下所示的資訊記錄訊息:

Kotlin

private const val TAG = "MyActivity"
...
Log.i(TAG, "MyClass.getView() — get item number $position")

Java

private static final String TAG = "MyActivity";
...
Log.i(TAG, "MyClass.getView() — get item number " + position);

注意事項:標記名稱如果超出 23 個字元,則 logcat 輸出內容顯示時會加以裁剪。

Logcat 訊息格式

所有 Android 記錄訊息都有標記和優先順序。系統記錄訊息的標記是短字串,說明導致發生此訊息的系統元件 (例如:ActivityManager)。任何感覺有用的字串都可以設成使用者定義標記,如目前類別名稱 (這是推薦建立的標記) 等等。比方說,您可以在 Log 方法呼叫中定義:

Kotlin

Log.d(tag, message)

Java

Log.d(tag, message);

可能出現的優先順序內容值有:

  • V: 詳細資訊 (優先順序最低)
  • D:偵錯
  • I:資訊
  • W:警示
  • E:錯誤
  • A:斷言

記錄訊息格式為:

date time PID-TID/package priority/tag: message

舉例來說,以下記錄訊息的優先順序是 V,並設有 AuthZen 標記:

12-10 13:02:50.071 1901-4229/com.google.android.gms V/AuthZen: Handling delegate intent.

PID 代表程序 ID,而 TID 代表執行緒 ID,如果只有一個執行緒,那這兩者也可以是相同內容。

設定記錄層級

設定記錄層級即可控制 logcat 顯示的訊息數量。您可以顯示所以訊息,也可以只顯示發生最嚴重問題的訊息。

切記,無論記錄層級設定為何,logcat 都會持續收集所有訊息。設定只能控制 logcat 的顯示方式。

在「Log level」(記錄層級) 選單中選擇以下任一種內容值:

  • 「Verbose」(詳細資訊):顯示所有記錄訊息 (預設值)。
  • 「Debug」(偵錯):顯示偵錯記錄訊息,以及本清單中低於此層級的訊息,這些訊息只對開發有幫助。
  • 「Info」(資訊):顯示一般使用上預期會看到的記錄訊息,以及本清單中低於此層級的訊息。
  • 「Warn」(警示):顯示還不會發生錯誤的可能問題,以及本清單中低於此層級的訊息。
  • 「Error」(錯誤):顯示會發生錯誤的問題,以及本清單中低於此層級的訊息。
  • 「Assert」(斷言):顯示開發人員認為不應該發生的問題。

搜尋 logcat 訊息

如何搜尋目前在 logcat 中顯示的訊息:

  1. 如果您想使用規則運算式搜尋模式,也可以點選「Regex」(規則運算式)。
  2. 在搜尋欄位 裡輸入文字串。

    logcat 輸出內容會按照輸入內容調整。

  3. 按下 Enter 鍵即可在選單中儲存這次工作階段的搜尋字串。
  4. 如果要再度搜尋,請從搜尋選單點選。按照需求選取或取消選取「Regex」(規則運算式) (系統不會記住這個設定)。

篩選 logcat 訊息

您可以使用篩選條件限制輸出內容,把輸出的記錄限制在方便管理的數量內。

注意事項:篩選條件會套用到所有 logcat 歷史記錄,不是只有 logcat 目前顯示的訊息。務必確認其他顯示項目設定正確無誤,才能看到想檢視的篩選輸出內容。

如何定義和套用篩選條件:

  1. 在篩選條件選單中選取篩選條件選項:
    • 「Show only selected application」(只顯示所選的應用程式):只顯示應用程式程式碼產生的訊息 (預設值)。Logcat 會使用作用中應用程式的 PID 篩選記錄訊息。
    • 「No Filters」(無篩選條件):不套用任何篩選條件。無論您所選擇的程序為何,Logcat 會顯示所有來自裝置的記錄訊息。
    • 「Edit Filter Configuration」(編輯篩選條件設定):建立或修改自訂篩選條件。例如,您可以建立篩選條件,藉此同時查看兩個應用程式的記錄訊息。

    定義篩選條件後,您也可以在選單中選擇。如果要移除選單內的項目,請刪除即可。

  2. 如果您選擇「Edit Filter Configuration」(編輯篩選條件設定),就可以建立或修改篩選條件了:
    1. 在「Create New Logcat Filter」(建立新的 Logcat 篩選條件) 對話方塊中撰寫篩選條件參數:
      • 「Filter Name」(篩選條件名稱):輸入您想定義的篩選條件名稱,或從左方窗格選取現有的篩選條件進行修改。名稱只能使用小寫字元、半形底線和數字。
      • 「Log Tag」(記錄標記):可選擇指定一個標記。詳情請參閱 logcat 訊息格式
      • 「Log Message」(記錄訊息):可選擇指定記錄訊息文字。詳情請參閱 logcat 訊息格式
      • 「Package Name」(套件名稱):可選擇指定一個套件名稱。詳情請參閱 logcat 訊息格式
      • 「PID」:可選擇指定一個程序 ID。詳情請參閱 logcat 訊息格式
      • 「Log Level」(記錄層級):可選擇一個記錄層級。詳情請參閱設定記錄層級
      • 「Regex」(規則運算式):選取這個選項後,該參數即可使用規則運算式語法。
    2. 按一下 + 即可在左方窗格新增篩選條件定義。

      如果想移除篩選條件,請從左方窗格點選,然後按一下 -

    3. 完成後,請按一下「OK」。

如果您看不到想找的記錄訊息,請嘗試選取「No Filters」(無篩選條件),然後再搜尋特定記錄訊息。

讀取垃圾收集訊息

有時發生垃圾收集事件時,也會列印到 logcat。

如要進一步瞭解應用程式記憶體,請用記憶體分析器

Dalvik 記錄訊息

在 Dalvik (不含 ART) 中,每項 GC 都會將下列資訊列印到 logcat:

D/dalvikvm(PID): GC_Reason Amount_freed, Heap_stats, External_memory_stats, Pause_time

範例:

D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms
GC 原因
GC 觸發原因,以及收集類型。可能出現的原因有:
GC_CONCURRENT
堆積開始填滿時,並行的 GC 青出了記憶體。
GC_FOR_MALLOC
由於應用程式嘗試在堆積已經全滿的情況下分配記憶體,導致系統必須停止應用程式並透過 GC 收回記憶體。
GC_HPROF_DUMP_HEAP
您要求建立 HPROF 檔案分析堆積,此時發生 GC。
GC_EXPLICIT
明確 GC,譬如當您呼叫 gc() 的時候 (您應該避免進行呼叫,相信 GC 會在需要的時候執行)。
GC_EXTERNAL_ALLOC
這只會在 API 級別 10 以下的情況下發生 (較新的版本會在 Dalvik 堆積分配所有資源)。外部分配記憶體的 GC (如儲存在本機記憶體的像素資料或 NIO 位元組緩衝區)。
釋出數量
這項 GC 收回的記憶體數量。
堆積統計資料
無堆積和 (活動中物件數量)/(總堆積大小) 的百分比。
外部記憶體統計資料
使用 API 級別 10 以下的外部分配記憶體 (分配記憶體數量) / (收集發生限制)。
暫停時間
較大的堆積會產生較長的暫停時間。並行暫停時間會顯示兩組暫停:一個位於收集開始時,另一個在即將結束時。

隨著這些記錄訊息累積起來,您也要注意堆積統計資料 (上面範例的 3571K/9991K 內容值) 的增長。如果這個值持續增加,可能表示發生記憶體流失。

ART 記錄訊息

與 Dalvik 不同的是,ART 不會記錄 GC 未明確要求的訊息。系統只會在判斷 GC 速度過慢時才會列印,說得更清楚一點,就是指 GC 暫停超過 5ms,或是 GC 時間超過 100ms 時。如果應用程式不在可以感受到暫停的狀態下 (例如當應用程式在背景執行時,使用者便無法察覺發生 GC 暫停),那麼這些 GC 都不會被系統認為速度過慢。系統一律會記錄明顯的 GC。

ART 在垃圾收集記錄訊息中提供下列資訊:

I/art: GC_Reason GC_Name Objects_freed(Size_freed) AllocSpace Objects,
    Large_objects_freed(Large_object_size_freed) Heap_stats LOS objects, Pause_time(s)

範例:

I/art : Explicit concurrent mark sweep GC freed 104710(7MB) AllocSpace objects,
    21(416KB) LOS objects, 33% free, 25MB/38MB, paused 1.230ms total 67.216ms
GC 原因
GC 觸發原因,以及收集類型。可能出現的原因有:
Concurrent
並未暫停應用程式執行緒的並行 GC。這項 GC 在背景執行緒中執行,不會妨礙分配。
Alloc
由於應用程式嘗試在堆積已經全滿的情況下分配記憶體,於是系統啟動 GC。在這種情況下,垃圾收集會在分配執行緒中發生。
Explicit
應用程式明確要求垃圾收集,例如呼叫 gc()gc()。和 Dalvik 一樣,使用 ART 的最佳做法就是相信 GC,儘量避免要求明確 GC。明確 GC 會封鎖分配執行緒,並會用沒必要的方式浪費 CPU 循環,因此不建議使用。明確 GC 也可能會造成其他執行緒先占,而導致資源浪費 (延遲、顫動或停止應用程式)。
NativeAlloc
由於本機分配導致的本機記憶體壓力,如點陣圖或 RenderScript 分配物件等,而導致發生收集。
CollectorTransition
堆積轉換導致發生收集,如果您在執行階段變更 GC 原則 (例如在可感受暫停狀態之間變更應用程式) 便會這樣。收集轉換內容會複製自由表空間的所有物件,並貼到觸碰傳輸指標空間 (或反過來)。

只有 Android 8.0 之前的低 RAM 裝置才會發生此情形,當應用程式的程序狀態從可感受暫停狀態 (如應用程式在前景執行時,此時使用者可以察覺 GC 暫停) 變為無法感受暫停狀態時 (或反過來) 就會如此。

HomogeneousSpaceCompact
同質空間密集是當自由表空間和自由表空間密集的情況,這通常是在應用程式從無法感受暫停的程序狀態改為其他狀態時會發生的情況。這麼做的主要原因是降低 RAM 使用率,以及整理堆積。
DisableMovingGc
這不是真的 GC 原因,只是說明由於在發生並行堆積密集的時候使用 GetPrimitiveArrayCritical 導致收集遭到封鎖。一般來說,我們非常不建議您使用 GetPrimitiveArrayCritical,它對移動收集工具有所限制。
HeapTrim
這不是真的 GC 原因,只是說明由於堆積修剪結束,所以收集遭到封鎖。
GC 名稱
ART 有各種可以執行的 GC。
Concurrent mark sweep (CMS)
收集整個堆積的工具,會釋出所有空間,不含圖像空間。
Concurrent partial mark sweep
收集幾乎整個堆積的工具,會收集除了圖像和 zygote 空間之外的空間。
Concurrent sticky mark sweep
產生的收集工具,只能收集上次 GC 後分配到的自由物件。這項垃圾收集速度較快,暫停時間也較短,所以比完整或部分標註清除還要更常執行。
Marksweep + semispace
非並行的複製 GC,負責堆積轉換和同質空間密集 (以便整理堆積)。
釋出物件
這項 GC 從非大型物件空間中收回的物件數量。
釋出大小
這項 GC 從非大型物件空間中收回的位元組數量。
釋出大型物件
這項垃圾收集從大型物件空間中收回的物件數量。
釋出大型物件大小
這項垃圾收集從大型物件空間中收回的位元組數量。
堆積統計資料
釋出和 (活動中物件數量)/(總堆積大小) 的百分比。
暫停時間
一般來說,暫停時間和執行 GC 時修改的物件參照數量成正比。目前 ART CMS GC 只會暫停一次,在 GC 快結束時發生。移動的 GC 暫停較長,佔了大部分的 GC 時間。

如果您在 logcat 看到大量 GC,您也要注意堆積統計資料 (上面範例的 25MB/38MB 內容值) 的增長。如果這個值持續增加,而不會減少,可能表示發生記憶體流失。另外,如果您看到 GC 原因為「Alloc」,表示您即將達到堆積容量上限,應該很快就會發生 OOM 例外狀況。