เอกสารนี้จะช่วยคุณระบุและแก้ไขปัญหาด้านประสิทธิภาพที่สำคัญในแอป
ปัญหาด้านประสิทธิภาพที่สำคัญ
มีหลายปัญหาที่อาจทำให้ประสิทธิภาพในแอปไม่ดี แต่ปัญหาที่พบบ่อยซึ่งควรตรวจสอบมีดังนี้
- เวลาในการตอบสนองของการเริ่มต้น
เวลาในการตอบสนองเมื่อเริ่มต้นคือระยะเวลาที่ใช้ตั้งแต่ การแตะไอคอนแอป การแจ้งเตือน หรือจุดแรกเข้าอื่นๆ ไปจนถึง ข้อมูลของผู้ใช้ที่แสดงบนหน้าจอ
มุ่งเน้นเป้าหมายการเริ่มต้นใช้งานต่อไปนี้ในแอป
- Cold Start ในเวลาน้อยกว่า 500 มิลลิวินาที Cold Start จะเกิดขึ้นเมื่อแอปที่กำลังเปิดตัวไม่ได้อยู่ในหน่วยความจำของระบบ เหตุการณ์นี้จะเกิดขึ้นเมื่อเป็นครั้งแรกที่แอปเปิดขึ้นนับตั้งแต่รีบูตหรือนับตั้งแต่ที่ผู้ใช้หรือระบบหยุดกระบวนการของแอป Cold Start ต้องใช้การทำงานจากระบบมากที่สุด เนื่องจากต้องโหลดทุกอย่างจากพื้นที่เก็บข้อมูลและเริ่มต้นแอป พยายามทำให้ Cold Start ใช้เวลา 500 มิลลิวินาทีหรือน้อยกว่า
- Warm Start ในเวลาน้อยกว่า 200 มิลลิวินาที และ Hot Start ในเวลาน้อยกว่า 150 มิลลิวินาที การเริ่มต้นแบบอุ่น เกิดขึ้นเมื่อกระบวนการของแอปพลิเคชันทำงานอยู่เบื้องหลัง แล้ว แต่ระบบต้องเริ่มต้น UI ใหม่หรือนำ กิจกรรมกลับมาที่เบื้องหน้า เช่น เมื่อผู้ใช้ออกจากแอปและ เปิดแอปอีกครั้งในเวลาต่อมา Hot Startจะเร็วกว่าเนื่องจากระบบแคชกิจกรรมของแอปไว้ในหน่วยความจำแล้ว และเพียงแค่นำมาไว้ที่เบื้องหน้าโดยไม่ต้องสร้างลำดับชั้นการแสดงผลใหม่ พยายามรักษา การเริ่มต้นแบบวอร์มให้ต่ำกว่า 200 มิลลิวินาที และการเริ่มต้นแบบฮอตให้ต่ำกว่า 150 มิลลิวินาที
- เวลาในการตอบสนอง P95 และ P99 ใกล้เคียงกับเวลาในการตอบสนองตามค่ามัธยฐานมาก P95 และ P99 แสดงถึงเปอร์เซ็นไทล์ที่ 95 และ 99 ของเวลาเริ่มต้น ส่วนค่ามัธยฐาน คือเปอร์เซ็นไทล์ที่ 50 เมื่อแอปใช้เวลานานในการเริ่มต้น ผู้ใช้จะได้รับ ประสบการณ์ที่ไม่ดี การสื่อสารระหว่างกระบวนการ (IPC) และ I/O ที่ไม่จำเป็น ในระหว่างเส้นทางวิกฤตของการเริ่มต้นแอปอาจทำให้เกิดการแย่งชิงล็อกและ ทำให้เกิดความไม่สอดคล้องกัน
- การเลื่อนกระตุก
Jank เป็นคำที่อธิบายอาการภาพกระตุกที่เกิดขึ้นเมื่อระบบสร้างและแสดงเฟรมไม่ทันเวลาเพื่อวาดลงบนหน้าจอตามอัตราการรีเฟรชที่ขอ 60 Hz ขึ้นไป อาการกระตุกจะเห็นได้ชัดที่สุดเมื่อเลื่อนหน้าจอ ซึ่งแทนที่จะเป็นการไหลที่ราบรื่นและเคลื่อนไหวได้ แต่กลับ มีการสะดุด อาการกระตุกจะเกิดขึ้นเมื่อการเคลื่อนไหวหยุดชั่วคราวระหว่างทางเป็นเวลา 1 เฟรมขึ้นไป เนื่องจากแอปใช้เวลานานกว่าในการแสดงเนื้อหาเมื่อเทียบกับระยะเวลาของเฟรมในระบบ
กำหนดเป้าหมายอัตราการรีเฟรช 90Hz ในแอป อัตราการแสดงผลทั่วไปคือ 60Hz แต่ในอุปกรณ์รุ่นใหม่ๆ จำนวนมากจะทำงานในโหมด 90Hz ระหว่างการโต้ตอบของผู้ใช้ เช่น การเลื่อน อุปกรณ์บางรุ่นรองรับอัตราที่สูงกว่านี้ถึง 120Hz
หากต้องการดูว่าอุปกรณ์ใช้อัตราการรีเฟรชใดในขณะนั้น ให้เปิดใช้การวางซ้อนโดยใช้ตัวเลือกสำหรับนักพัฒนาแอป > แสดงอัตราการรีเฟรชในส่วนการแก้ไขข้อบกพร่อง
- ทรานซิชันไม่ราบรื่น
ซึ่งจะเห็นได้ชัดเจนในระหว่างการโต้ตอบ เช่น การสลับระหว่างแท็บหรือการโหลดกิจกรรมใหม่ การเปลี่ยนฉากประเภทนี้ ต้องเป็นภาพเคลื่อนไหวที่ราบรื่นและไม่มีความล่าช้าหรือภาพกะพริบ
- ประสิทธิภาพการใช้พลังงานต่ำ
การทำงานจะลดการชาร์จแบตเตอรี่และท้ายที่สุดก็ลด อายุการใช้งานแบตเตอรี่
การจัดสรรหน่วยความจำซึ่งมาจากการสร้างออบเจ็กต์ใหม่ในโค้ดทำให้เกิดการทำงาน ในระบบ การจัดสรรเองไม่เพียงต้องใช้ความพยายามจาก Android Runtime (ART) เท่านั้น แต่การปล่อยออบเจ็กต์เหล่านี้ในภายหลัง (การเก็บขยะ) ก็ต้องใช้เวลาและความพยายามด้วย
ทั้งการจัดสรรหน่วยความจำและระบบจัดการหน่วยความจำที่ไม่ใช้แล้วจะเร็วขึ้นและมีประสิทธิภาพมากขึ้น โดยเฉพาะอย่างยิ่งสำหรับออบเจ็กต์ชั่วคราว แม้ว่าในอดีต แนวทางปฏิบัติแนะนำคือการหลีกเลี่ยงการจัดสรรออบเจ็กต์ทุกครั้งที่ทำได้ แต่เราขอแนะนำ ให้คุณทำสิ่งที่เหมาะสมที่สุดสำหรับแอปและสถาปัตยกรรมของคุณ การประหยัดการจัดสรรโดยเสี่ยงต่อโค้ดที่ดูแลรักษาไม่ได้ไม่ใช่แนวทางปฏิบัติที่ดีที่สุด เมื่อพิจารณาถึงความสามารถของ ART
อย่างไรก็ตาม การจัดสรรต้องใช้ความพยายาม ดังนั้นโปรดทราบว่าการจัดสรรออบเจ็กต์จำนวนมากในลูปด้านในอาจทำให้เกิดปัญหาด้านประสิทธิภาพ
ระบุปัญหา
หากต้องการแก้ไขปัญหาด้านประสิทธิภาพ ให้ระบุและตรวจสอบเส้นทางของผู้ใช้ที่สําคัญต่อไปนี้
- โฟลว์การเริ่มต้นใช้งานทั่วไป รวมถึงจากตัวเรียกใช้และการแจ้งเตือน
- หน้าจอที่ผู้ใช้เลื่อนดูข้อมูล
- การเปลี่ยนระหว่างหน้าจอ
- โฟลว์ที่ทำงานเป็นเวลานาน เช่น การนำทางหรือการเล่นเพลง
สําหรับโฟลว์แต่ละรายการ ให้ตรวจสอบสิ่งที่เกิดขึ้นโดยใช้เครื่องมือแก้ไขข้อบกพร่องต่อไปนี้
- Perfetto: ช่วยให้คุณเห็นสิ่งที่เกิดขึ้นในอุปกรณ์ทั้งเครื่องด้วย ข้อมูลการจับเวลาที่แม่นยำ
- เครื่องมือสร้างโปรไฟล์หน่วยความจำ: ช่วยให้คุณเห็นการจัดสรรหน่วยความจำที่เกิดขึ้นในฮีป
- Simpleperf: แสดง Flame Graph ของการเรียกฟังก์ชันที่ใช้ CPU มากที่สุดในช่วงระยะเวลาหนึ่ง เมื่อคุณพบว่ามีบางอย่างใน Systrace ที่ใช้เวลานาน แต่ไม่ทราบสาเหตุ Simpleperf จะให้ข้อมูลเพิ่มเติมได้
การแก้ไขข้อบกพร่องของการทดสอบแต่ละครั้งด้วยตนเองเป็นสิ่งสำคัญอย่างยิ่งในการทำความเข้าใจและแก้ไขข้อบกพร่องเกี่ยวกับประสิทธิภาพเหล่านี้ คุณไม่สามารถแทนที่ขั้นตอนก่อนหน้าด้วยการวิเคราะห์ข้อมูลที่รวบรวมแล้วได้ อย่างไรก็ตาม หากต้องการทราบว่าผู้ใช้เห็นอะไรจริงๆ และ ระบุเวลาที่อาจเกิดการถดถอย คุณควรตั้งค่าการรวบรวมเมตริก ในการทดสอบอัตโนมัติและในภาคสนาม
- โฟลว์การเริ่มต้นใช้งาน
- เมตริกฟิลด์: เวลาเริ่มต้นของ Play Console
- การทดสอบในห้องทดลอง: ทดสอบการเริ่มต้นด้วย Macrobenchmark
- Jank
- เมตริกภาคสนาม
- Vitals ของเฟรมใน Play Console: คุณไม่สามารถจำกัดเมตริกให้แคบลงเพื่อเจาะจงเส้นทางของผู้ใช้ที่เฉพาะเจาะจงภายใน Play Console ได้ โดยจะรายงานเฉพาะ Jank โดยรวม ทั่วทั้งแอป
- การวัดที่กำหนดเองด้วย
FrameMetricsAggregator: คุณใช้FrameMetricsAggregatorเพื่อบันทึกเมตริก Jank ระหว่างเวิร์กโฟลว์ ที่เฉพาะเจาะจงได้
- การตรวจในห้องทดลอง
- การเลื่อนด้วย Macrobenchmark
- Macrobenchmark จะรวบรวมเวลาเฟรมโดยใช้
dumpsys gfxinfoคำสั่งที่ครอบคลุมเส้นทางของผู้ใช้เดียว ซึ่งเป็นวิธี ทำความเข้าใจความผันผวนของ Jank ในเส้นทางของผู้ใช้ที่เฉพาะเจาะจงRenderTimeเมตริกที่ไฮไลต์ระยะเวลาที่เฟรมใช้ในการ วาดมีความสำคัญมากกว่าจำนวนเฟรมที่กระตุกสําหรับ การระบุการถดถอยหรือการปรับปรุง
- เมตริกภาคสนาม
ปัญหาเกี่ยวกับการยืนยัน App Link
App Link คือ Deep Link ตาม URL ของเว็บไซต์ที่ได้รับการยืนยันแล้วว่าเป็นของเว็บไซต์ของคุณ การยืนยัน App Link อาจไม่สำเร็จด้วยสาเหตุต่อไปนี้
- ขอบเขตตัวกรอง Intent ไม่ถูกต้อง: เพิ่ม
autoVerifyลงในตัวกรอง Intent สำหรับ URL ที่แอปตอบสนองได้เท่านั้น - การเปลี่ยนโปรโตคอลที่ไม่ได้รับการยืนยัน: การเปลี่ยนเส้นทางฝั่งเซิร์ฟเวอร์และโดเมนย่อยที่ไม่ได้รับการยืนยันถือเป็นความเสี่ยงด้านความปลอดภัยและจะยืนยันไม่สำเร็จ ซึ่งทำให้ลิงก์
autoVerifyทั้งหมดใช้งานไม่ได้ เช่น การเปลี่ยนเส้นทางลิงก์จาก HTTP ไปยัง HTTPS เช่น example.com ไปยัง www.example.com โดยไม่ยืนยันลิงก์ HTTPS อาจทำให้การยืนยันล้มเหลว โปรดยืนยัน App Link โดยการ เพิ่มตัวกรอง Intent - ลิงก์ที่ยืนยันไม่ได้: การเพิ่มลิงก์ที่ยืนยันไม่ได้เพื่อวัตถุประสงค์ในการทดสอบ อาจทำให้ระบบไม่ยืนยัน App Link สำหรับแอปของคุณ
- เซิร์ฟเวอร์ที่ไม่น่าเชื่อถือ: ตรวจสอบว่าเซิร์ฟเวอร์เชื่อมต่อกับแอปไคลเอ็นต์ได้
ตั้งค่าแอปเพื่อการวิเคราะห์ประสิทธิภาพ
การตั้งค่าอย่างเหมาะสมเป็นสิ่งสำคัญเพื่อให้ได้เกณฑ์เปรียบเทียบที่แม่นยำ ทำซ้ำได้ และนำไปใช้ได้จริง จากแอป ทดสอบในระบบที่ใกล้เคียงกับเวอร์ชันที่ใช้งานจริงมากที่สุด ในขณะที่ระงับแหล่งที่มาของสัญญาณรบกวน ส่วนต่อไปนี้แสดงขั้นตอนเฉพาะสำหรับ APK และระบบที่คุณทำได้เพื่อเตรียมการตั้งค่าการทดสอบ ซึ่งบางขั้นตอนจะเฉพาะเจาะจงสำหรับกรณีการใช้งาน
Tracepoint
แอปสามารถวัดโค้ดด้วยเหตุการณ์การติดตามที่กำหนดเอง
ในขณะที่บันทึกการติดตาม การติดตามจะทำให้เกิดค่าใช้จ่ายเพิ่มเติมเล็กน้อยประมาณ 5μs ต่อส่วน ดังนั้นจึงไม่ควรใส่การติดตามไว้ในทุกๆ เมธอด การติดตามงานขนาดใหญ่กว่า 0.1 มิลลิวินาทีจะช่วยให้ได้ข้อมูลเชิงลึกที่สำคัญเกี่ยวกับคอขวด
ข้อควรพิจารณาเกี่ยวกับ APK
ตัวแปรการแก้ไขข้อบกพร่องมีประโยชน์ในการแก้ปัญหาและสัญลักษณ์ตัวอย่างสแต็ก
แต่ส่งผลกระทบอย่างรุนแรงต่อประสิทธิภาพ อุปกรณ์ที่ใช้ Android 10 (API
ระดับ 29) ขึ้นไปสามารถใช้ profileable android:shell="true" ใน
ไฟล์ Manifest เพื่อเปิดใช้การสร้างโปรไฟล์ในบิลด์ที่เผยแพร่
ใช้การกำหนดค่าการลดขนาดโค้ดระดับเวอร์ชันที่ใช้งานจริง ซึ่งอาจส่งผลต่อประสิทธิภาพอย่างมาก ทั้งนี้ขึ้นอยู่กับ ทรัพยากรที่แอปใช้ การกำหนดค่า ProGuard บางรายการจะนำจุดติดตามออก ดังนั้นโปรดพิจารณานำกฎเหล่านั้นออกสำหรับการกำหนดค่าที่คุณใช้ทดสอบ
การรวบรวม
คอมไพล์แอปในอุปกรณ์ให้อยู่ในสถานะที่ทราบ โดยทั่วไปคือ speed เพื่อความ
เรียบง่าย หรือ speed-profile เพื่อให้ตรงกับประสิทธิภาพในเวอร์ชันที่ใช้งานจริงมากขึ้น
(แม้ว่าการดำเนินการนี้จะต้องมีการวอร์มอัปแอปพลิเคชันและทิ้งโปรไฟล์ หรือ
คอมไพล์โปรไฟล์พื้นฐานของแอป)
ทั้ง speed และ speed-profile จะลดปริมาณโค้ดที่ทำงานซึ่งตีความจาก DEX และส่งผลให้ปริมาณการคอมไพล์แบบ Just-In-Time (JIT) ในเบื้องหลังลดลง ซึ่งอาจทำให้เกิดการรบกวนอย่างมาก เฉพาะ speed-profile
เท่านั้นที่ลดผลกระทบของการโหลดคลาสรันไทม์จาก Dex
คำสั่งต่อไปนี้จะคอมไพล์แอปพลิเคชันโดยใช้โหมด speed
adb shell cmd package compile -m speed -f com.example.packagename
speedโหมดการคอมไพล์
speed-profileโหมดจะคอมไพล์เมธอดและคลาสของแอปตาม
โปรไฟล์ของเส้นทางโค้ดที่ใช้ซึ่งรวบรวมไว้ในระหว่างการใช้งานแอป การรวบรวมโปรไฟล์อย่างสม่ำเสมอและถูกต้องอาจเป็นเรื่องยาก ดังนั้นหากคุณตัดสินใจที่จะใช้โปรไฟล์ ให้ตรวจสอบว่าโปรไฟล์รวบรวมข้อมูลตามที่คุณคาดหวัง โปรไฟล์จะอยู่ในตำแหน่งต่อไปนี้
/data/misc/profiles/ref/[package-name]/primary.prof
ข้อควรพิจารณาเกี่ยวกับระบบ
หากต้องการการวัดระดับต่ำและความเที่ยงตรงสูง ให้ปรับเทียบอุปกรณ์ ทำการเปรียบเทียบ A/B ในอุปกรณ์เดียวกันและระบบปฏิบัติการเวอร์ชันเดียวกัน ประสิทธิภาพอาจแตกต่างกันอย่างมาก แม้จะเป็นอุปกรณ์ประเภทเดียวกันก็ตาม
ในอุปกรณ์ที่รูทแล้ว ให้ลองใช้สคริปต์ lockClocks สำหรับ
Microbenchmarks สคริปต์เหล่านี้จะทำสิ่งต่างๆ ต่อไปนี้
- วาง CPU ที่ความถี่คงที่
- ปิดใช้คอร์ขนาดเล็กและกำหนดค่า GPU
- ปิดใช้การควบคุมอุณหภูมิ
เราไม่แนะนำให้ใช้lockClocksสคริปต์สำหรับการทดสอบที่เน้นประสบการณ์ของผู้ใช้
เช่น การทดสอบการเปิดแอป การทดสอบ DoU และการทดสอบ Jank แต่สคริปต์นี้อาจจำเป็นสำหรับ
การลดสัญญาณรบกวนในการทดสอบ Microbenchmark
หากเป็นไปได้ ให้พิจารณาใช้เฟรมเวิร์กการทดสอบ เช่น Macrobenchmark ซึ่งจะช่วยลดสัญญาณรบกวนในการวัดผลและป้องกันความไม่ถูกต้องของการวัดผล
การเริ่มต้นแอปช้า: กิจกรรมแทรมโพลีนที่ไม่จำเป็น
กิจกรรม Trampoline อาจขยายเวลาเริ่มต้นของแอปโดยไม่จำเป็น และคุณควรทราบว่าแอปของคุณทำเช่นนี้หรือไม่ ดังที่แสดงในตัวอย่างต่อไปนี้
การติดตาม activityStart จะตามด้วย activityStart อีกรายการทันที
โดยที่กิจกรรมแรกไม่ได้วาดเฟรมใดๆ
รูปที่ 1 ร่องรอยที่แสดงกิจกรรมแทรมโพลีน
ปัญหานี้อาจเกิดขึ้นได้ทั้งในจุดแรกเข้าของการแจ้งเตือนและจุดแรกเข้าของการเริ่มต้นแอปตามปกติ และคุณมักจะแก้ไขได้ด้วยการปรับโครงสร้างโค้ด ตัวอย่างเช่น หากคุณ ใช้กิจกรรมนี้เพื่อทำการตั้งค่าก่อนที่กิจกรรมอื่นจะทำงาน ให้แยกโค้ดนี้ ออกเป็นคอมโพเนนต์หรือไลบรารีที่นำกลับมาใช้ใหม่ได้
การจัดสรรที่ไม่จำเป็นซึ่งทำให้เกิด GC บ่อยครั้ง
คุณอาจเห็นการเก็บขยะ (GC) เกิดขึ้นบ่อยกว่าที่คาดไว้ใน Systrace
ในตัวอย่างต่อไปนี้ ระบบจัดการหน่วยความจำที่ไม่ใช้แล้วทุกๆ 10 วินาทีระหว่างการดำเนินการที่ใช้เวลานานเป็นตัวบ่งชี้ว่าแอปอาจจัดสรรโดยไม่จำเป็นแต่สม่ำเสมอเมื่อเวลาผ่านไป
รูปที่ 2 การติดตามที่แสดงช่องว่างระหว่างเหตุการณ์ GC
นอกจากนี้ คุณอาจสังเกตเห็นในเครื่องมือสร้างโปรไฟล์หน่วยความจำว่าสแต็กการเรียกใช้ที่เฉพาะเจาะจงทำให้เกิดการจัดสรรส่วนใหญ่ คุณไม่จำเป็นต้องกำจัดการจัดสรรทั้งหมดอย่างจริงจัง เนื่องจากอาจทำให้โค้ดดูแลรักษายากขึ้น แต่ให้ เริ่มจากการทำงานกับฮอตสปอตของการจัดสรร
เฟรมที่กระตุก
ไปป์ไลน์กราฟิกค่อนข้างซับซ้อน และอาจมีรายละเอียดบางอย่างในการพิจารณาว่าผู้ใช้จะเห็นเฟรมที่ขาดหายไปหรือไม่ ในบางกรณี แพลตฟอร์มสามารถ "กู้" เฟรมได้โดยใช้การบัฟเฟอร์ อย่างไรก็ตาม คุณสามารถละเว้นรายละเอียดส่วนใหญ่ เพื่อระบุเฟรมที่มีปัญหาจากมุมมองของแอปได้
เมื่อมีการวาดเฟรมโดยที่แอปไม่ต้องทำงานมาก
Choreographer.doFrame() จุดติดตามจะเกิดขึ้นทุกๆ 16.7 มิลลิวินาทีในอุปกรณ์ 60 FPS
รูปที่ 3 การติดตามที่แสดงเฟรมเร็วที่เกิดขึ้นบ่อย
หากซูมออกและไปยังส่วนต่างๆ ของการติดตาม คุณอาจเห็นเฟรมใช้เวลานานขึ้นเล็กน้อยในการแสดงผล แต่ไม่เกินเวลาที่กำหนดไว้ 16.7 มิลลิวินาที เฟรมต่อไปนี้ใช้ได้
รูปที่ 4 การติดตามที่แสดงเฟรมเร็วบ่อยๆ พร้อมการทำงานเป็นช่วงๆ
เมื่อเห็นว่าจังหวะปกติเกิดการหยุดชะงัก แสดงว่าเฟรมไม่เสถียร ดังที่แสดง ในรูปที่ 5 และ 6
รูปที่ 5 การติดตามที่แสดงเฟรมที่กระตุก
รูปที่ 6 การติดตามที่แสดงเฟรมที่กระตุกมากขึ้น
ในบางกรณี คุณต้องซูมเข้าที่จุดติดตามเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับ
คอมโพเนนต์ UI ที่ Compose อัปเดต หรือดูว่า LazyColumn กำลังทำอะไรอยู่ ดังที่แสดงในรูปที่ 6 เมื่อวินิจฉัยคอขวดของ UI เหล่านี้ การติดตามระบบมาตรฐานอาจไม่แสดง Composable ที่เป็นสาเหตุที่แท้จริง ในกรณีเหล่านี้ ให้ใช้การติดตามการคอมโพสของ Jetpack Compose ซึ่งจะแสดงฟังก์ชันที่คอมโพสได้ที่แน่นอน
โดยตรงภายในร่องรอย ทำให้ระบุการคอมโพสใหม่ที่ไม่คาดคิดได้ง่ายขึ้น
รูปที่ 5 และ 6 แสดงผลลัพธ์ของการติดตามการคอมโพสิต
ดูข้อมูลเพิ่มเติมเกี่ยวกับการเพิ่มประสิทธิภาพ Compose ได้ที่ประสิทธิภาพของ Jetpack Compose ดูข้อมูลเพิ่มเติมเกี่ยวกับการระบุเฟรมที่กระตุกและ การแก้ไขข้อบกพร่องของสาเหตุได้ที่การแสดงผลช้า
ข้อผิดพลาดที่พบบ่อยเกี่ยวกับเลย์เอาต์แบบเลื่อน
การลบล้างสถานะการสนับสนุนทั้งหมดของเลย์เอาต์แบบ Lazy โดยไม่จำเป็นอาจ ทำให้เกิดการประกอบใหม่มากเกินไป เวลาในการแสดงผลเฟรมที่นาน และการกระตุก หากต้องการลดจำนวนรายการในลิสต์ที่ต้องอัปเดต ให้ใช้คีย์รายการสำหรับ รายการของคุณ และเปลี่ยนเฉพาะองค์ประกอบสถานะที่เฉพาะเจาะจงที่เปลี่ยนแปลง
ดูใช้คีย์เลย์เอาต์แบบ Lazy เพื่อดูวิธีหลีกเลี่ยงการจัดสรรรายการทั้งหมดใหม่ที่มีค่าใช้จ่ายสูง ซึ่งทำให้เนื้อหาอัปเดตแทนที่จะแทนที่ทั้งหมด
การติดตั้งรายการเลื่อนที่ซ้อนกันอย่างไม่เหมาะสมอาจทำให้ประสิทธิภาพลดลง หลีกเลี่ยงการซ้อนเลย์เอาต์แบบเลื่อนที่โหลดแบบ Lazy ภายในคอนเทนเนอร์การเลื่อนอื่นโดยไม่มี ข้อจำกัดที่ชัดเจน ดูข้อมูลเพิ่มเติมได้ที่หลีกเลี่ยงการซ้อนคอมโพเนนต์ที่เลื่อนได้ในทิศทางเดียวกัน
การดึงข้อมูลล่วงหน้าไม่เพียงพอหรือดึงข้อมูลล่วงหน้าไม่ทันเวลาอาจทำให้ การเลื่อนไปที่ด้านล่างของรายการเลื่อนไม่ราบรื่นเมื่อผู้ใช้ต้องรอ ข้อมูลเพิ่มเติมจากเซิร์ฟเวอร์ แม้ว่าในทางเทคนิคแล้วนี่จะไม่ใช่ Jank เนื่องจากไม่มีการพลาดกำหนดเวลาของเฟรม แต่คุณก็ปรับปรุง UX ได้อย่างมากด้วยการแก้ไขเวลาและปริมาณการดึงข้อมูลล่วงหน้าเพื่อให้ผู้ใช้ไม่ต้องรอข้อมูล
แก้ไขข้อบกพร่องของแอป
ต่อไปนี้คือวิธีการแก้ไขข้อบกพร่องของประสิทธิภาพแอป
แก้ไขข้อบกพร่องของการเริ่มต้นแอปด้วย Systrace
ดูภาพรวมของกระบวนการเริ่มต้นแอปได้ที่เวลาเริ่มต้นแอป และดูภาพรวมของการติดตามระบบและการใช้ Android Studio Profiler ได้ในวิดีโอต่อไปนี้
คุณสามารถแยกประเภทสตาร์ทอัปได้ในขั้นตอนต่อไปนี้
- Cold Startup: เริ่มต้นด้วยการสร้างกระบวนการใหม่ที่ไม่มีสถานะที่บันทึกไว้
- Warm Startup: สร้างกิจกรรมใหม่ขณะใช้กระบวนการซ้ำ หรือ สร้างกระบวนการใหม่ด้วยสถานะที่บันทึกไว้
- Hot Startup: รีสตาร์ทกิจกรรมและเริ่มที่การเพิ่มค่า
เราขอแนะนำให้บันทึก Systrace ด้วยแอปการติดตามระบบในอุปกรณ์ สำหรับ Android 10 ขึ้นไป ให้ใช้ Perfetto สำหรับ Android 9 และต่ำกว่า ให้ใช้ Systrace นอกจากนี้ เราขอแนะนำให้ดูไฟล์การติดตามด้วยโปรแกรมดูการติดตาม Perfetto บนเว็บ ดูข้อมูลเพิ่มเติมได้ที่ภาพรวมของการติดตามระบบ
โดยอิงตามสิ่งที่ควรพิจารณาดังนี้
- ตรวจสอบการแย่งชิง: การแข่งขันเพื่อทรัพยากรที่ได้รับการปกป้องโดยการตรวจสอบอาจทำให้เกิด ความล่าช้าอย่างมากในการเริ่มต้นแอป
ธุรกรรม Binder แบบซิงโครนัส: มองหาธุรกรรมที่ไม่จำเป็นในเส้นทางสำคัญของแอป หากธุรกรรมที่จำเป็นมีค่าใช้จ่ายสูง ให้พิจารณาทำงานร่วมกับทีมแพลตฟอร์มที่เกี่ยวข้องเพื่อทำการปรับปรุง
GC พร้อมกัน: ปัญหานี้พบได้ทั่วไปและมีผลกระทบค่อนข้างน้อย แต่หากพบปัญหานี้บ่อยครั้ง ให้ลองตรวจสอบด้วยโปรไฟล์เลอร์หน่วยความจำของ Android Studio
I/O: ตรวจสอบ I/O ที่ดำเนินการระหว่างการเริ่มต้นระบบ และมองหาการหยุดทำงานเป็นเวลานาน
กิจกรรมสำคัญในเธรดอื่นๆ: กิจกรรมเหล่านี้อาจรบกวนเธรด UI ดังนั้นโปรดระวังงานในเบื้องหลังระหว่างการเริ่มต้น
เราขอแนะนำให้คุณเรียกใช้ reportFullyDrawn เมื่อการเริ่มต้นเสร็จสมบูรณ์จากมุมมองของแอปเพื่อปรับปรุงการรายงานเมตริกการเริ่มต้นแอป ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ reportFullyDrawn ได้ที่ส่วนเวลา
ในการแสดงผลทั้งหมด
คุณสามารถดึงเวลาเริ่มต้นที่กำหนดโดย RFD ผ่านตัวประมวลผลการติดตาม Perfetto
และจะมีการปล่อยเหตุการณ์การติดตามที่ผู้ใช้มองเห็น
ใช้การติดตามระบบในอุปกรณ์
คุณสามารถใช้แอปที่ระดับระบบที่เรียกว่าการติดตามระบบเพื่อบันทึกการติดตามระบบในอุปกรณ์ แอปนี้ช่วยให้คุณบันทึกร่องรอยจากอุปกรณ์ได้โดยไม่ต้องเสียบปลั๊กหรือเชื่อมต่อกับ adb
ใช้เครื่องมือสร้างโปรไฟล์หน่วยความจำของ Android Studio
คุณใช้ Android Studio Memory Profiler เพื่อตรวจสอบแรงกดดันด้านหน่วยความจำ ที่อาจเกิดจากการรั่วไหลของหน่วยความจำหรือรูปแบบการใช้งานที่ไม่ดีได้ ซึ่งแสดงมุมมองแบบเรียลไทม์ของการจัดสรรออบเจ็กต์
คุณแก้ไขปัญหาหน่วยความจำในแอปได้โดยใช้เครื่องมือสร้างโปรไฟล์หน่วยความจำเพื่อติดตามสาเหตุและความถี่ที่ GC เกิดขึ้น
หากต้องการสร้างโปรไฟล์หน่วยความจำของแอป ให้ทำตามขั้นตอนต่อไปนี้
ตรวจหาปัญหาเกี่ยวกับหน่วยความจำ
บันทึกเซสชันการสร้างโปรไฟล์หน่วยความจำของเส้นทางของผู้ใช้ที่คุณต้องการโฟกัส มองหาจำนวนออบเจ็กต์ที่เพิ่มขึ้น ดังที่แสดงในรูปที่ 7 ซึ่งในที่สุดจะ ทำให้เกิด GC ดังที่แสดงในรูปที่ 8
รูปที่ 7 เพิ่มจำนวนออบเจ็กต์
รูปที่ 8 การเก็บขยะหลังจากระบุเส้นทางของผู้ใช้ที่เพิ่มแรงกดดันด้านหน่วยความจำแล้ว ให้วิเคราะห์สาเหตุหลักของแรงกดดันด้านหน่วยความจำ
วินิจฉัยจุดที่เกิดปัญหาหน่วยความจำ
เลือกช่วงในไทม์ไลน์เพื่อแสดงภาพทั้งการจัดสรรและ ขนาดแบบตื้น ดังที่แสดงในรูปที่ 9
รูปที่ 9 ค่าสำหรับ Allocations และ Shallow
Sizeคุณจัดเรียงข้อมูลนี้ได้หลายวิธี ต่อไปนี้คือตัวอย่าง วิธีที่แต่ละมุมมองช่วยวิเคราะห์ปัญหาได้
จัดเรียงตามคลาส: มีประโยชน์เมื่อคุณต้องการค้นหาคลาสที่ สร้างออบเจ็กต์ที่แคชหรือนำกลับมาใช้ใหม่จากพูลหน่วยความจำ
เช่น หากแอปสร้างออบเจ็กต์ 2,000 รายการของคลาสหนึ่งๆ ทุกวินาที ระบบจะเพิ่มจำนวนการจัดสรร 2,000 รายการ ทุกวินาที และคุณจะเห็นเมื่อจัดเรียงตามคลาส หากต้องการนำออบเจ็กต์เหล่านี้กลับมาใช้ใหม่เพื่อหลีกเลี่ยงการสร้างขยะ ให้ใช้พูลหน่วยความจำ
จัดเรียงตาม Callstack: มีประโยชน์เมื่อคุณต้องการค้นหาตำแหน่งที่มี Hotpath ซึ่งมีการจัดสรรหน่วยความจำ เช่น ภายในลูปหรือภายในฟังก์ชันที่เฉพาะเจาะจงซึ่งทำงานด้านการจัดสรรเป็นจำนวนมาก
ขนาดแบบตื้น: ติดตามเฉพาะหน่วยความจำของออบเจ็กต์เอง ซึ่งมีประโยชน์ ในการติดตามคลาสอย่างง่ายที่ประกอบด้วยค่าดั้งเดิมเป็นส่วนใหญ่
ขนาดที่เก็บไว้: แสดงหน่วยความจำทั้งหมดเนื่องจากออบเจ็กต์เองรวมถึงการอ้างอิงใดๆ ที่ออบเจ็กต์อ้างอิงเท่านั้น ซึ่งมีประโยชน์ในการติดตามแรงกดดันด้านหน่วยความจำเนื่องจากออบเจ็กต์ที่ซับซ้อน หากต้องการรับค่านี้ ให้ทำ การดัมพ์หน่วยความจำทั้งหมด ดังที่แสดงในรูปที่ 10 ระบบจะเพิ่มขนาดที่คงไว้เป็นคอลัมน์ ดังที่แสดงในรูปที่ 11
รูปที่ 10 การทิ้งหน่วยความจำทั้งหมด
รูปที่ 11 คอลัมน์ขนาดที่คงไว้
วัดผลกระทบของการเพิ่มประสิทธิภาพ
GC จะชัดเจนยิ่งขึ้นและวัดผลกระทบของการเพิ่มประสิทธิภาพในหน่วยความจำได้ง่ายขึ้น เมื่อการเพิ่มประสิทธิภาพช่วยลดแรงกดดันด้านหน่วยความจำ คุณจะเห็น GC น้อยลง
หากต้องการวัดผลกระทบของการเพิ่มประสิทธิภาพ ให้วัด เวลาที่ใช้ระหว่าง GC ในไทม์ไลน์ของโปรไฟล์เลอร์ ผลกระทบเชิงบวกส่งผลให้ระยะเวลาระหว่าง GC นานขึ้น
ผลกระทบขั้นสุดท้ายของการปรับปรุงหน่วยความจำมีดังนี้
- การปิดระบบเนื่องจากหน่วยความจำไม่เพียงพอมีแนวโน้มที่จะลดลงหากแอปไม่ได้ ใช้หน่วยความจำจนเต็มอยู่ตลอดเวลา
- การมี GC น้อยลงจะช่วยปรับปรุงเมตริกความกระตุก โดยเฉพาะใน P99 เนื่องจาก GC ทำให้เกิดการแย่งชิง CPU ซึ่งอาจทำให้ระบบเลื่อนงานการแสดงผลออกไปในขณะที่ GC กำลังทำงาน
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- การวิเคราะห์และการเพิ่มประสิทธิภาพการเริ่มต้นแอป {:#app-startup-analysis-optimization}
- เฟรมที่ค้าง
- เขียน Macrobenchmark