เครื่องมือและวิธีการใดของ Android ที่ทำงานได้ดีที่สุดในการค้นหาการรั่วไหลของหน่วยความจำ / ทรัพยากร [ปิด]


152

ฉันได้พัฒนาแอพ Android และฉันเป็นจุดพัฒนาแอปโทรศัพท์ที่ทุกอย่างทำงานได้ดีและคุณต้องการประกาศชัยชนะและส่ง แต่คุณรู้ว่าต้องมีหน่วยความจำและทรัพยากรรั่วไหล ในนั้น; และมีเพียง 16mb จำนวนมากบน Android และเห็นได้ชัดว่ามันง่ายที่จะรั่วไหลในแอพ Android

ฉันได้ดูไปรอบ ๆ และจนถึงตอนนี้สามารถขุดข้อมูลใน 'hprof' และ 'traceview' เท่านั้นและไม่ได้รับรีวิวที่น่าพอใจมากมาย

คุณมีเครื่องมือหรือวิธีการใดบ้างที่พบหรือพัฒนาและสนใจที่จะแบ่งปันในโครงการระบบปฏิบัติการ


3
ฉันสามารถลงคะแนนให้ Р̀СТȢѸ́ФХѾЦЧШЩЪЫЬѢѤЮѦѪѨѬѠѺѮѰѲѴ เปลี่ยนชื่อของเขาเป็นสิ่งที่มนุษย์อ่านได้หรือไม่
JPM

1
มันจะโอเคที่จะเปิดคำถามนี้อีกครั้งถ้าเราลบคำว่า "เครื่องมือ Android" ออกจากคำถาม? คำตอบที่พบในที่นี้ค่อนข้างมีประโยชน์ในการแก้ไขปัญหาการรั่วไหลของหน่วยความจำของฉัน
k3b

ตกลงดังนั้นฉันมีผู้ใช้สลับระหว่างกิจกรรมอย่างต่อเนื่องซึ่งหมายความว่าพวกเขาอาจสลับ 15 กิจกรรมใน 20 วินาที นั่นอาจเป็นสาเหตุของข้อผิดพลาดหน่วยความจำไม่เพียงพอหรือไม่ ฉันควรทำอย่างไรเพื่อแก้ไข ขอบคุณ!
Ruchir Baronia

1
ไม่สามารถให้การตอบสนองนี้เป็นเพราะคำถามที่ได้รับการปิด แต่ฉันขอแนะนำให้ดูที่รั่วเกาะคานารี เพียงใช้แอพเปิดและปิดกิจกรรมและปล่อยให้ห้องสมุดทำงานได้ มันจะบอกคุณด้วยว่ามีรอยรั่วเกิดขึ้นที่ไหน เพียงแค่ให้เครื่องวิเคราะห์การรั่วไหลสักครู่เพื่อทำงานหลังจากการรั่วไหลเกิดขึ้น - โดยปกติจะใช้เวลาประมาณ 2 นาทีหรือมากกว่านั้นจนกว่าจะพบแหล่งที่มาของการรั่วไหล หลังจากนั้นมันจะนำเสนอให้คุณในแอปอย่างเรียบร้อย ไม่จำเป็นต้องใช้เครื่องมือพิเศษ!
ubuntudroid

คำตอบ:


90

หนึ่งในข้อผิดพลาดที่พบบ่อยที่สุดที่ฉันพบในการพัฒนา Android Apps คือข้อผิดพลาด“ java.lang.OutOfMemoryError: บิตแมปขนาดเกินงบประมาณ VM” ฉันพบข้อผิดพลาดนี้อย่างอิสระในกิจกรรมที่ใช้บิตแมปจำนวนมากหลังจากเปลี่ยนการวางแนว: กิจกรรมถูกทำลายสร้างขึ้นอีกครั้งและโครงร่าง“ พองตัว” จาก XML ที่ใช้หน่วยความจำ VM ที่พร้อมใช้งานสำหรับบิตแมป

บิตแมปในโครงร่างกิจกรรมก่อนหน้านี้ไม่ได้ถูกจัดสรรคืนอย่างถูกต้องโดยตัวรวบรวมขยะเนื่องจากมีการอ้างอิงข้ามกับกิจกรรมของพวกเขา หลังจากการทดลองหลายครั้งฉันพบวิธีแก้ปัญหาที่ค่อนข้างดีสำหรับปัญหานี้

ก่อนอื่นให้ตั้งค่าแอตทริบิวต์“ id” ในมุมมองพาเรนต์ของโครงร่าง XML ของคุณ:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:id="@+id/RootView"
     >
     ...

จากนั้นในเมธอด onDestroy () ของกิจกรรมของคุณให้เรียกเมธอด unbindDrawables () ผ่านการอ้างอิงไปที่มุมมองพาเรนต์แล้วทำ System.gc ()

@Override
protected void onDestroy() {
    super.onDestroy();

    unbindDrawables(findViewById(R.id.RootView));
    System.gc();
}


private void unbindDrawables(View view) {

    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }

    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }

        ((ViewGroup) view).removeAllViews();
    }
}

เมธอด unbindDrawables () นี้สำรวจแผนผังมุมมองแบบวนซ้ำและ:

  1. ลบการเรียกกลับใน drawable พื้นหลังทั้งหมด
  2. ลบ childs ในทุกกลุ่มการดู

3
วิธีแก้ไขปัญหาทั่วไปที่ดี
ในขณะที่ -E

9
สิ่งนี้ใช้ไม่ได้กับคลาสย่อยของ AdapterView (ListView, GridView และอื่น ๆ )
อาร์จัน

@Arjun ใช่.. มันใช้ไม่ได้กับคลาสย่อยของ AdapterView เพื่อที่คุณจะต้องจัดการกับข้อยกเว้น ส่วนที่เหลือมันทำงานได้ดี นั่นคือสิ่งที่ฉันใช้ในรหัสของฉันและใช้งานได้ดี หวังว่านี่จะช่วยได้
hp.android

@ hp.android โดย "จัดการสิ่งนี้ในข้อยกเว้น" คุณมีตัวอย่างของสิ่งที่จะมีลักษณะอย่างไร ฉันถามเพราะฉันมีหน้าของภาพในของฉันPageAdapterและฉันได้รับการแก้ไขโดยข้อผิดพลาดนี้ :(
Jacksonkr

4
@ แจ็คสันเพียงแค่เปลี่ยนเงื่อนไข: ถ้า (ดูอินสแตนซ์ของ ViewGroup &&! (ดูอินสแตนซ์ของ AdapterView)) สิ่งนี้จะกำจัดข้อยกเว้นที่คุณได้รับสำหรับอะแดปเตอร์
hp.android


28

ส่วนใหญ่สำหรับนักเดินทางของ Google จากอนาคต:

เครื่องมือจาวาส่วนใหญ่ไม่เหมาะสำหรับงานนี้เนื่องจากพวกเขาวิเคราะห์ JVM-Heap เท่านั้น แอพพลิเคชั่น Android ทุกตัวนั้นมีฮีปดั้งเดิมอยู่ด้วยซึ่งจะต้องมีขนาดไม่เกิน ~ 16 MB มันมักจะใช้สำหรับข้อมูลบิตแมปเช่น ดังนั้นคุณสามารถเรียกใช้ข้อผิดพลาด Out Of Memory ได้อย่างง่ายดายแม้ว่า JVM-Heap ของคุณจะชิลลินประมาณ 3 MB หากคุณใช้ drawable จำนวนมาก


6
การเริ่มต้น drawable สำหรับ Android 3.0 (รวงผึ้ง) จะถูกเก็บไว้ในกอง
Gu1234

@Timo แล้วคุณจะใช้อะไรในการตรวจหารอยรั่วในฮีปดั้งเดิม
sydd

1
การทดสอบการทดสอบมากมาย ปัญหาคือคุณไม่สามารถบอกได้เลยว่าหน่วยความจำของแอปของคุณกำลังใช้งานเท่าไหร่เนื่องจากการแชร์หน่วยความจำและเทคนิคการเพิ่มประสิทธิภาพอื่น คุณสามารถรับการอ่านหน่วยความจำโดยใช้คำสั่งเชลล์ปกติ แต่สิ่งเหล่านั้นเป็นการประมาณคร่าวๆ
Timo Ohr

20

คำตอบจาก @ hp.android ทำงานได้ดีถ้าคุณเป็นเพียงการทำงานที่มีภูมิหลังบิตแมป แต่ในกรณีของฉันฉันมีBaseAdapterให้ชุดของImageViews GridViewสำหรับ ฉันปรับเปลี่ยนunbindDrawables()วิธีการตามที่แนะนำเพื่อให้สภาพเป็น:

if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
  ...
}

AdapterViewแต่ปัญหาก็คือว่าวิธีการเรียกซ้ำไม่เคยกระบวนการเด็กของ เพื่อแก้ไขปัญหานี้ฉันได้ทำสิ่งต่อไปนี้:

if (view instanceof ViewGroup) {
  ViewGroup viewGroup = (ViewGroup) view;
  for (int i = 0; i < viewGroup.getChildCount(); i++)
    unbindDrawables(viewGroup.getChildAt(i));

  if (!(view instanceof AdapterView))
    viewGroup.removeAllViews();
}

เพื่อให้ลูก ๆ ของAdapterViewยังคงดำเนินการ - วิธีการเพียงไม่พยายามลบเด็ก ๆ (ซึ่งไม่ได้รับการสนับสนุน)

มันไม่ได้ช่วยแก้ไขปัญหาได้มากนักเนื่องจากImageViewจัดการบิตแมปที่ไม่ใช่พื้นหลัง ฉันจึงเพิ่มสิ่งต่อไปนี้ มันไม่เหมาะ แต่ใช้งานได้:

if (view instanceof ImageView) {
  ImageView imageView = (ImageView) view;
  imageView.setImageBitmap(null);
}

โดยรวมแล้วunbindDrawables()วิธีการคือ:

private void unbindDrawables(View view) {
  if (view.getBackground() != null)
    view.getBackground().setCallback(null);

  if (view instanceof ImageView) {
    ImageView imageView = (ImageView) view;
    imageView.setImageBitmap(null);
  } else if (view instanceof ViewGroup) {
    ViewGroup viewGroup = (ViewGroup) view;
    for (int i = 0; i < viewGroup.getChildCount(); i++)
    unbindDrawables(viewGroup.getChildAt(i));

    if (!(view instanceof AdapterView))
      viewGroup.removeAllViews();
  }
}

ฉันหวังว่าจะมีวิธีการที่ชัดเจนยิ่งขึ้นในการเพิ่มทรัพยากร


12

พูดคุย Google I / O ได้ดี (2011) เกี่ยวกับการจัดการหน่วยความจำใน Android รวมถึงรายละเอียดเกี่ยวกับเครื่องมือ + เทคนิคสำหรับการสร้างโปรไฟล์หน่วยความจำ:
http://www.youtube.com/watch?v=_CruQY55HOk


4
หรือโพสต์บล็อกที่เกี่ยวข้อง: android-developers.blogspot.com/2011/03/…
greg7gkb

1
ตกลงดังนั้นฉันมีผู้ใช้สลับระหว่างกิจกรรมอย่างต่อเนื่องซึ่งหมายความว่าพวกเขาอาจสลับ 15 กิจกรรมใน 20 วินาที นั่นอาจเป็นสาเหตุของข้อผิดพลาดหน่วยความจำไม่เพียงพอหรือไม่ ฉันควรทำอย่างไรเพื่อแก้ไข ขอบคุณ!'
Ruchir Baronia


1

นี่เป็นเครื่องมือที่เชื่อมโยงกับรูปแบบที่เป็นเอกลักษณ์ที่ Android ใช้ .. ฉันคิดว่าสิ่งที่คุณอาจไม่พึงพอใจคือกรอบการทดสอบพื้นฐานที่ใช้อยู่ ..

คุณลองจำลองพื้นที่ทดสอบของรหัสโดยใช้ Android Mock Framework หรือไม่?


1
ไม่มากการทดสอบลักษณะนั้นไม่ได้เป็นปัญหามากนักขณะบันทึกสิ่งที่เกิดขึ้นจริงในขณะที่แอปพลิเคชันทำงานสิ่งที่ฉันต้องการจริงๆคือเครื่องมือทำโปรไฟล์การรั่วไหลของทรัพยากร / หน่วยความจำ
jottos
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.