ฉันจะค้นหาการใช้งานหน่วยความจำของแอปพลิเคชันของฉันใน Android ได้อย่างไร


800

ฉันจะค้นหาหน่วยความจำที่ใช้กับแอปพลิเคชัน Android ของฉันได้โดยทางโปรแกรมอย่างไร

ฉันหวังว่าจะมีวิธีที่จะทำ นอกจากนี้ฉันจะรับหน่วยความจำฟรีของโทรศัพท์ได้อย่างไร


2
หรือหากใครต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้กรุณาอ้างอิงhttp://elinux.org/Android_Memory_Usage

คำตอบ:


1008

โปรดทราบว่าการใช้หน่วยความจำบนระบบปฏิบัติการสมัยใหม่เช่น Linux นั้นเป็นพื้นที่ที่ซับซ้อนและยากต่อการเข้าใจ ในความเป็นจริงโอกาสที่คุณจะตีความตัวเลขใด ๆ ที่คุณได้รับนั้นต่ำมาก (ค่อนข้างทุกครั้งที่ฉันดูหมายเลขการใช้หน่วยความจำกับวิศวกรคนอื่น ๆ มีการพูดคุยกันนานเกี่ยวกับสิ่งที่พวกเขาจริง ๆ แล้วหมายความว่าจะส่งผลให้เกิดข้อสรุปที่คลุมเครือเท่านั้น)

หมายเหตุ: ตอนนี้เรามีเอกสารมากมายเกี่ยวกับการจัดการหน่วยความจำของแอพของคุณซึ่งครอบคลุมเนื้อหาส่วนใหญ่ที่นี่และเป็นข้อมูลล่าสุดเกี่ยวกับสถานะของ Android

สิ่งแรกคือการอ่านส่วนสุดท้ายของบทความนี้ซึ่งมีการอภิปรายบางส่วนเกี่ยวกับวิธีการจัดการหน่วยความจำบน Android:

การเปลี่ยนแปลง API บริการเริ่มต้นด้วย Android 2.0

ตอนนี้ActivityManager.getMemoryInfo()เป็น API ระดับสูงสุดของเราสำหรับการดูการใช้งานหน่วยความจำโดยรวม นี่เป็นส่วนใหญ่ที่จะช่วยให้แอพพลิเคชั่นเกจว่าระบบใกล้จะมาถึงที่จะไม่มีหน่วยความจำมากขึ้นสำหรับกระบวนการพื้นหลังดังนั้นจึงจำเป็นต้องเริ่มต้นฆ่ากระบวนการที่ต้องการเช่นบริการ สำหรับแอพพลิเคชั่นจาวาล้วนๆสิ่งนี้ควรใช้เพียงเล็กน้อยเนื่องจากขีด จำกัด ของฮีพของ Java อยู่ในส่วนหนึ่งเพื่อหลีกเลี่ยงหนึ่งแอพที่จะทำให้ระบบเครียดจนถึงจุดนี้

การลดระดับลงคุณสามารถใช้ Debug API เพื่อรับข้อมูลระดับเคอร์เนลแบบดิบเกี่ยวกับการใช้หน่วยความจำ: android.os.Debug.MemoryInfo

หมายเหตุเริ่มต้นด้วย 2.0 นอกจากนี้ยังมี API ActivityManager.getProcessMemoryInfoเพื่อรับข้อมูลนี้เกี่ยวกับกระบวนการอื่น: ActivityManager.getProcessMemoryInfo (int [])

ส่งคืนโครงสร้าง MemoryInfo ระดับต่ำที่มีข้อมูลทั้งหมดนี้:

    /** The proportional set size for dalvik. */
    public int dalvikPss;
    /** The private dirty pages used by dalvik. */
    public int dalvikPrivateDirty;
    /** The shared dirty pages used by dalvik. */
    public int dalvikSharedDirty;

    /** The proportional set size for the native heap. */
    public int nativePss;
    /** The private dirty pages used by the native heap. */
    public int nativePrivateDirty;
    /** The shared dirty pages used by the native heap. */
    public int nativeSharedDirty;

    /** The proportional set size for everything else. */
    public int otherPss;
    /** The private dirty pages used by everything else. */
    public int otherPrivateDirty;
    /** The shared dirty pages used by everything else. */
    public int otherSharedDirty;

แต่เป็นสิ่งที่แตกต่างระหว่างPss, PrivateDirtyและSharedDirty... ดีตอนนี้สนุกจะเริ่มขึ้น

หน่วยความจำจำนวนมากใน Android (และระบบ Linux โดยทั่วไป) มีการใช้งานร่วมกันจริงในหลาย ๆ กระบวนการ ดังนั้นจำนวนหน่วยความจำที่กระบวนการใช้นั้นไม่ชัดเจนจริงๆ เพิ่มเพจนั้นลงบนดิสก์ (ให้สลับอย่างเดียวซึ่งเราไม่ได้ใช้บน Android) และชัดเจนน้อยกว่า

ดังนั้นถ้าคุณใช้ RAM จริงทั้งหมดที่แมปในแต่ละกระบวนการและรวมกระบวนการทั้งหมดคุณอาจจะต้องจบลงด้วยจำนวนที่มากกว่า RAM ทั้งหมดที่เกิดขึ้นจริง

Pssจำนวนเป็นตัวชี้วัดคำนวณเคอร์เนลที่จะเข้าสู่การแชร์หน่วยความจำบัญชี - พื้นหน้าของ RAM ในแต่ละกระบวนการที่มีการปรับสัดส่วนโดยอัตราส่วนของจำนวนของกระบวนการอื่น ๆ ที่ยังมีการใช้หน้านั้น วิธีนี้คุณสามารถเพิ่ม pss ในกระบวนการทั้งหมดเพื่อดู RAM ทั้งหมดที่ใช้และเปรียบเทียบ pss ระหว่างกระบวนการเพื่อให้เข้าใจถึงน้ำหนักสัมพัทธ์

ตัวชี้วัดที่น่าสนใจอื่น ๆ ที่นี่คือPrivateDirtyซึ่งโดยทั่วไปคือปริมาณของ RAM ภายในกระบวนการที่ไม่สามารถทำเพจได้กับดิสก์ (ไม่ได้รับการสนับสนุนจากข้อมูลบนดิสก์เดียวกัน) และไม่ถูกแชร์กับกระบวนการอื่น ๆ อีกวิธีในการดูนี่คือ RAM ที่จะพร้อมใช้งานกับระบบเมื่อกระบวนการนั้นหายไป (และอาจรวมเข้ากับแคชและการใช้งานอื่นอย่างรวดเร็ว)

นั่นเป็น SDK APIs ที่ค่อนข้างดีสำหรับเรื่องนี้ อย่างไรก็ตามมีมากกว่าที่คุณสามารถทำได้ในฐานะนักพัฒนาซอฟต์แวร์ด้วยอุปกรณ์ของคุณ

การใช้adbมีข้อมูลจำนวนมากที่คุณสามารถรับเกี่ยวกับการใช้หน่วยความจำของระบบที่กำลังทำงานอยู่ หนึ่งที่พบบ่อยคือคำสั่งadb shell dumpsys meminfoที่จะคายออกข้อมูลมากมายเกี่ยวกับการใช้หน่วยความจำของแต่ละกระบวนการ Java ที่มีข้อมูลข้างต้นเช่นเดียวกับความหลากหลายของสิ่งอื่น ๆ นอกจากนี้คุณยังสามารถตรึงชื่อหรือ pid ของกระบวนการเดียวที่จะเห็นตัวอย่างเช่นadb shell dumpsys meminfo systemให้กระบวนการฉัน:

** MEMINFO ใน pid 890 [ระบบ] **
                    native dalvik รวมทั้งหมด
            ขนาด: 10940 7047 N / A 17987
       จัดสรร: 8943 5516 N / A 14459
            ฟรี: 336 1531 N / A 1867
           (Pss): 4585 9282 11916 25783
  (แบ่งปันสกปรก): 2184 3596 916 6696
    (สกปรกสกปรก): 4504 5956 7456 17916

 วัตถุ
           Views: 149 ViewRoots: 4
     AppContexts: 13 กิจกรรม: 0
          สินทรัพย์: 4 ผู้จัดการสินทรัพย์: 4
   Local Binders: 141 Binder proxy: 158
ผู้รับความตาย: 49
 Sockets OpenSSL: 0

 SQL
            กอง: 205 dbFiles: 0
       numPagers: 0 inactivePageKB: 0
    activePageKB: 0

ส่วนด้านบนเป็นส่วนหลักซึ่งsizeขนาดโดยรวมในพื้นที่ที่อยู่ของฮีปหนึ่ง ๆallocatedคือ kb ของการจัดสรรจริงที่ฮีปคิดว่ามีfreeอยู่คือ kb ที่เหลือฟรีฮีพที่มีสำหรับการจัดสรรเพิ่มเติมpssและpriv dirtyเป็นแบบเดียวกัน ตามที่กล่าวไว้ก่อนหน้าเฉพาะหน้าที่เกี่ยวข้องกับแต่ละฮีป

adb shell procrankถ้าคุณเพียงต้องการที่จะดูที่การใช้งานหน่วยความจำผ่านกระบวนการทั้งหมดที่คุณสามารถใช้คำสั่ง ผลลัพธ์ของสิ่งนี้ในระบบเดียวกันดูเหมือนว่า:

  PID Vss Rss Pss ใช้ cmdline
  890 84456K 48668K 25850K 21284K system_server
 1231 50748K 39088K 17587K 13792K com.android.launcher2
  947 34488K 28528K 10834K 9308K com.android.wallpaper
  987 26964K 26956K 8751K 7308K com.google.process.gapps
  954 24300K ​​24296K 6249K 4824K com.android.phone
  948 23020K 23016K 5864K 4748K com.android.inputmethod.latin
  888 25728K 25724K 5774K 3668K zygote
  977 24100K 24096K 5667K 4340K android.process.acore
...
   59 336K 332K 99K 92K / system / bin / installd
   60 396K 392K 93K 84K / system / bin / keystore
   51 280K 276K 74K 68K / system / bin / servicemanager
   54 256K 252K 69K 64K / system / bin / debuggerd

ที่นี่VssและRssคอลัมน์เป็นเสียงรบกวน (เหล่านี้คือพื้นที่ที่อยู่ตรงไปข้างหน้าและการใช้ RAM ของกระบวนการซึ่งถ้าคุณเพิ่มการใช้ RAM ในกระบวนการที่คุณได้รับเป็นจำนวนมากอย่างน่าขัน)

Pssคือเท่าที่เราได้เห็นมาก่อนและเป็นUssPriv Dirty

สิ่งที่น่าสนใจที่จะต้องทราบที่นี่: PssและUssเล็กน้อย (หรือมากกว่าเล็กน้อย) meminfoแตกต่างจากสิ่งที่เราเห็นใน ทำไมถึงเป็นอย่างนั้น? procrank ดีใช้กลไกเคอร์เนลที่แตกต่างกันในการรวบรวมข้อมูลของมันmeminfoและพวกเขาให้ผลแตกต่างกันเล็กน้อย ทำไมถึงเป็นอย่างนั้น? สุจริตฉันไม่ได้เบาะแส ฉันเชื่อว่าprocrankอาจเป็นสิ่งที่ถูกต้องมากขึ้น ... แต่จริงๆแล้วนี่แค่ทิ้งประเด็นไว้: "เอาข้อมูลความทรงจำใด ๆ ที่คุณได้รับมาด้วยเกลือเม็ด; มักจะเป็นเมล็ดที่มีขนาดใหญ่มาก"

ในที่สุดก็มีคำสั่งadb shell cat /proc/meminfoที่ให้บทสรุปของการใช้หน่วยความจำโดยรวมของระบบ มีข้อมูลจำนวนมากที่นี่เพียงไม่กี่ตัวเลขแรกที่ควรพูดถึง (และคนที่เหลือที่เข้าใจโดยคนไม่กี่คนและคำถามของฉันเกี่ยวกับคนเหล่านั้นเกี่ยวกับพวกเขามักทำให้เกิดคำอธิบายที่ขัดแย้งกัน):

MemTotal: 395144 kB
MemFree: 184936 kB
บัฟเฟอร์: 880 kB
แคช: 84104 kB
SwapCached: 0 kB

MemTotal คือจำนวนหน่วยความจำทั้งหมดที่มีสำหรับเคอร์เนลและพื้นที่ผู้ใช้ (มักน้อยกว่า RAM จริงของอุปกรณ์เนื่องจาก RAM บางตัวนั้นจำเป็นสำหรับวิทยุบัฟเฟอร์ DMA และอื่น ๆ )

MemFreeคือจำนวน RAM ที่ไม่ได้ใช้งานเลย จำนวนที่คุณเห็นที่นี่สูงมาก โดยทั่วไปแล้วในระบบ Android จะเป็นเพียงไม่กี่ MB เนื่องจากเราพยายามใช้หน่วยความจำที่มีอยู่เพื่อให้กระบวนการทำงานต่อไป

Cachedเป็นแรมที่ใช้สำหรับแคชของระบบไฟล์และสิ่งอื่น ๆ ระบบทั่วไปจะต้องมี 20MB หรือมากกว่านั้นเพื่อหลีกเลี่ยงการเข้าสู่สถานะเพจไม่ดี Android killer หน่วยความจำไม่พอปรับสำหรับระบบเฉพาะเพื่อให้แน่ใจว่ากระบวนการพื้นหลังถูกฆ่าก่อนที่ RAM ที่แคชจะถูกใช้มากเกินไปโดยพวกเขาจะส่งผลให้เพจจิ้ง


1
ดูpixelbeat.org/scripts/ps_mem.pyซึ่งใช้เทคนิคที่กล่าวถึงข้างต้นเพื่อแสดง RAM ที่ใช้สำหรับโปรแกรม
pixelbeat

17
เขียนได้ดีมาก! ฉันเขียนโพสต์เกี่ยวกับการจัดการหน่วยความจำและการใช้เครื่องมือต่าง ๆ เพื่อตรวจสอบการใช้ฮีปของคุณที่นี่macgyverdev.blogspot.com/2011/11/…หากใครก็ตามพบว่ามันมีประโยชน์
Johan Norén

3
คอลัมน์ "dalvik" สองตัวคือ "ดั้งเดิม" คืออะไร
dacongy

1
"native" "dalvik" "other" คืออะไรกันแน่? ในแอปของฉัน "อื่น ๆ " มีขนาดใหญ่มากใช่ไหม ฉันจะลดมันได้อย่างไร
landry

ฉันสามารถใช้ "adb shell dumpsys meminfo" แต่ "adb shell procrank" บอกฉัน "/ system / bin / sh: procrank: ไม่พบ" ฉันยังไม่ได้เบาะแสคุณสามารถช่วยฉันได้
Hugo

79

ใช่คุณสามารถรับข้อมูลหน่วยความจำโดยทางโปรแกรมและตัดสินใจว่าจะใช้งานหน่วยความจำมากหรือไม่

รับ VM Heap Size โดยโทร:

Runtime.getRuntime().totalMemory();

รับหน่วยความจำ VM ที่จัดสรรโดยการโทร:

Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

รับ VM Heap Size Limit โดยโทร:

Runtime.getRuntime().maxMemory()

รับหน่วยความจำที่จัดสรรโดยการโทร:

Debug.getNativeHeapAllocatedSize();

ฉันสร้างแอพเพื่อหาพฤติกรรม OutOfMemoryError และตรวจสอบการใช้หน่วยความจำ

https://play.google.com/store/apps/details?id=net.coocood.oomresearch

คุณสามารถรับซอร์สโค้ดได้ที่ https://github.com/coocood/oom-research


7
รันไทม์นี้จะส่งคืนการใช้หน่วยความจำตามกระบวนการปัจจุบันหรือฮีปของระบบโดยรวมหรือไม่
Mahendran

1
@mahemadhi จาก JavaDoc ของวิธี totalMemory () "ส่งคืนจำนวนหน่วยความจำทั้งหมดที่มีให้กับโปรแกรมที่กำลังใช้งาน"
Alex

นี่ไม่ใช่คำตอบที่ถูกต้องสำหรับคำถาม คำตอบไม่ได้เกี่ยวกับแอปพลิเคชันเฉพาะ
Amir Rezazadeh

52

นี่คืองานที่กำลังดำเนินการ แต่นี่คือสิ่งที่ฉันไม่เข้าใจ:

ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);

Log.i(TAG, " memoryInfo.availMem " + memoryInfo.availMem + "\n" );
Log.i(TAG, " memoryInfo.lowMemory " + memoryInfo.lowMemory + "\n" );
Log.i(TAG, " memoryInfo.threshold " + memoryInfo.threshold + "\n" );

List<RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();

Map<Integer, String> pidMap = new TreeMap<Integer, String>();
for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses)
{
    pidMap.put(runningAppProcessInfo.pid, runningAppProcessInfo.processName);
}

Collection<Integer> keys = pidMap.keySet();

for(int key : keys)
{
    int pids[] = new int[1];
    pids[0] = key;
    android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
    for(android.os.Debug.MemoryInfo pidMemoryInfo: memoryInfoArray)
    {
        Log.i(TAG, String.format("** MEMINFO in pid %d [%s] **\n",pids[0],pidMap.get(pids[0])));
        Log.i(TAG, " pidMemoryInfo.getTotalPrivateDirty(): " + pidMemoryInfo.getTotalPrivateDirty() + "\n");
        Log.i(TAG, " pidMemoryInfo.getTotalPss(): " + pidMemoryInfo.getTotalPss() + "\n");
        Log.i(TAG, " pidMemoryInfo.getTotalSharedDirty(): " + pidMemoryInfo.getTotalSharedDirty() + "\n");
    }
}

เหตุใด PID จึงไม่แมปกับผลลัพธ์ใน activityManager.getProcessMemoryInfo () เห็นได้ชัดว่าคุณต้องการทำให้ข้อมูลผลลัพธ์มีความหมายดังนั้นทำไม Google จึงทำให้มันยากที่จะเชื่อมโยงผลลัพธ์? ระบบปัจจุบันทำงานได้ไม่ดีนักหากฉันต้องการประมวลผลการใช้หน่วยความจำทั้งหมดเนื่องจากผลลัพธ์ที่ส่งคืนเป็นอาร์เรย์ของวัตถุ android.os.Debug.MemoryInfo แต่ไม่มีวัตถุใดที่บอกให้คุณทราบว่ามีการเชื่อมโยงกับอะไร หากคุณผ่านไปในหลาย ๆ pids คุณจะไม่มีทางเข้าใจผลลัพธ์ ตามที่ฉันเข้าใจการใช้งานมันไม่มีความหมายเลยที่จะส่งผ่าน pid มากกว่าหนึ่งครั้งและถ้าเป็นกรณีนี้เหตุใดจึงต้องทำเช่นนั้นเพื่อให้ ActivityManager.getProcessMemoryInfo () ใช้อาร์เรย์ int เท่านั้น?


2
พวกมันกำลังอยู่ในลำดับเดียวกันกับอาร์เรย์อินพุต
taer

2
ดูเหมือนจะเป็นวิธีที่ไม่ง่ายในการทำสิ่งต่าง ๆ ใช่มันอาจเป็นไปได้ แต่ OOP ในทางใดทางหนึ่ง?
Ryan Beesley

6
API ได้รับการออกแบบมาเพื่อประสิทธิภาพไม่ใช้งานง่ายหรือไม่ซับซ้อน นี่ไม่ใช่สิ่งที่ 99% ของแอพควรสัมผัสดังนั้นประสิทธิภาพคือเป้าหมายการออกแบบที่สำคัญที่สุด
hackbod

2
ยุติธรรมพอสมควร ฉันกำลังพยายามเขียนเครื่องมือภายในเพื่อติดตามการใช้หน่วยความจำสำหรับแอปพลิเคชันที่เราเขียนอย่างน้อยหนึ่งรายการ เป็นผลให้ฉันกำลังมองหาวิธีที่จะทำการตรวจสอบนี้ในขณะที่ส่งผลกระทบต่อกระบวนการอื่น ๆ น้อยที่สุด แต่ยังคงมีรายละเอียดกับผลลัพธ์ที่เป็นไปได้ (หลังการประมวลผล) วนซ้ำกระบวนการและการโทรสำหรับแต่ละกระบวนการดูเหมือนจะไม่มีประสิทธิภาพสมมติว่ามีค่าใช้จ่ายสำหรับการเรียก. getProcessMemoryInfo แต่ละครั้ง หากอาร์เรย์ที่ส่งคืนได้รับการรับรองว่าอยู่ในลำดับเดียวกันกับการโทรฉันจะประมวลผลผลลัพธ์แบบสุ่มสี่สุ่มห้าและเพียงสมมติว่ามีความเท่าเทียมกัน
Ryan Beesley

5
นี่เป็นปัญหาเล็กน้อย แต่สำหรับบันทึกคุณไม่จำเป็นต้องเพิ่ม linefeed ที่จัดการให้คุณ
ThomasW

24

Hackbod's เป็นหนึ่งในคำตอบที่ดีที่สุดของ Stack Overflow มันพ่นแสงไปที่วัตถุที่คลุมเครือมาก มันช่วยฉันได้มาก

แหล่งข้อมูลที่มีประโยชน์จริง ๆ คือวิดีโอที่ต้องดู: Google I / O 2011: การจัดการหน่วยความจำสำหรับแอพ Android


UPDATE:

Process Stats บริการค้นหาวิธีที่แอพของคุณจัดการหน่วยความจำอธิบายที่โพสต์บล็อกProcess Process: ทำความเข้าใจว่าแอพของคุณใช้ RAMโดย Dianne Hackborn อย่างไร:


19

Android สตูดิโอ 0.8.10+ ได้แนะนำเครื่องมือที่มีประโยชน์อย่างไม่น่าเชื่อที่เรียกว่าหน่วยความจำการตรวจสอบ

ป้อนคำอธิบายรูปภาพที่นี่

สิ่งที่ดีสำหรับ:

  • แสดงหน่วยความจำที่มีอยู่และใช้แล้วในกราฟและเหตุการณ์การเก็บขยะเมื่อเวลาผ่านไป
  • ทดสอบอย่างรวดเร็วว่าแอพพลิเคชั่นความช้าอาจเกี่ยวข้องกับเหตุการณ์การรวบรวมขยะมากเกินไปหรือไม่
  • ทดสอบอย่างรวดเร็วว่าแอปขัดข้องอาจเกี่ยวข้องกับหน่วยความจำไม่เพียงพอหรือไม่

ป้อนคำอธิบายรูปภาพที่นี่

รูปที่ 1. บังคับให้เหตุการณ์ GC (รวบรวมขยะ) บน Android Memory Monitor

คุณสามารถมีข้อมูลที่ดีมากมายเกี่ยวกับการใช้ RAM แบบเรียลไทม์ของแอปโดยใช้มัน


16

1) ฉันเดาว่าอย่างน้อยก็ไม่ใช่จาก Java
2)

ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
activityManager.getMemoryInfo(mi);
Log.i("memory free", "" + mi.availMem);

1
เปลี่ยนเป็น (ActivityManager activityManager = (ActivityManager) getSystemService (ACTIVITY_SERVICE);) แทน (ActivityManager activityManager = = (ActivityManager) getSystemService (ACTIVITY_SERVICE);
Rajkamal

7

เราพบว่าวิธีมาตรฐานทั้งหมดในการรับหน่วยความจำทั้งหมดของกระบวนการปัจจุบันมีปัญหาบางอย่าง

  • Runtime.getRuntime().totalMemory(): ส่งคืนหน่วยความจำ JVM เท่านั้น
  • ActivityManager.getMemoryInfo(), Process.getFreeMemory()และสิ่งอื่นที่อยู่บนพื้นฐาน/proc/meminfo- ข้อมูลหน่วยความจำผลตอบแทนที่เกี่ยวกับกระบวนการทั้งหมดรวมกัน (เช่นandroid_util_Process.cpp )
  • Debug.getNativeHeapAllocatedSize()- ใช้mallinfo()ข้อมูลส่งคืนเกี่ยวกับการจัดสรรหน่วยความจำที่ดำเนินการโดยmalloc()และฟังก์ชันที่เกี่ยวข้องเท่านั้น (ดูandroid_os_Debug.cpp )
  • Debug.getMemoryInfo()- ทำงานได้ แต่ช้าเกินไป ใช้เวลาประมาณ200msในNexus 6สำหรับการโทรครั้งเดียว ค่าใช้จ่ายด้านประสิทธิภาพทำให้ฟังก์ชั่นนี้ไร้ประโยชน์สำหรับเราในขณะที่เราเรียกมันว่าเป็นประจำและทุกการโทรค่อนข้างชัดเจน (ดูandroid_os_Debug.cpp )
  • ActivityManager.getProcessMemoryInfo(int[])- โทรDebug.getMemoryInfo()ภายใน (ดูActivityManagerService.java )

สุดท้ายเราก็ใช้รหัสต่อไปนี้:

const long pageSize = 4 * 1024; //`sysconf(_SC_PAGESIZE)`
string stats = File.ReadAllText("/proc/self/statm");
var statsArr = stats.Split(new [] {' ', '\t', '\n'}, 3);

if( statsArr.Length < 2 )
    throw new Exception("Parsing error of /proc/self/statm: " + stats);

return long.Parse(statsArr[1]) * pageSize;

มันกลับVmRSSเมตริก คุณสามารถค้นหารายละเอียดเพิ่มเติมได้ที่นี่: หนึ่ง , สองและสาม


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

Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
long res = memInfo.getTotalPrivateDirty();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
    res += memInfo.getTotalPrivateClean(); 

return res * 1024L;


1

มีคำตอบมากมายที่ด้านบนซึ่งจะช่วยคุณได้อย่างแน่นอน แต่(หลังจาก 2 วันของการซื้อและการวิจัยเกี่ยวกับเครื่องมือหน่วยความจำ adb)ฉันคิดว่าฉันสามารถช่วยด้วยความเห็นของฉันเช่นกัน

ตามที่ Hackbod พูดว่า: ดังนั้นหากคุณใช้ RAM จริงทั้งหมดที่แมปเข้ากับแต่ละกระบวนการและเพิ่มกระบวนการทั้งหมดคุณอาจต้องจบลงด้วยจำนวน RAM ที่แท้จริงทั้งหมด ดังนั้นจึงไม่มีวิธีที่คุณจะได้รับจำนวนหน่วยความจำที่แน่นอนต่อกระบวนการ

แต่คุณสามารถเข้าใกล้มันได้ด้วยตรรกะบางอย่าง .. และฉันจะบอกวิธี ..

มีบางอย่างที่ชอบandroid.os.Debug.MemoryInfoและActivityManager.getMemoryInfo()กล่าวถึงข้างต้นซึ่งคุณอาจได้อ่านและใช้แล้ว แต่ฉันจะพูดถึงวิธีอื่น

ดังนั้นก่อนอื่นคุณต้องเป็นผู้ใช้รูทเพื่อให้มันใช้งานได้ ได้รับในคอนโซลที่มีสิทธิ์รากโดยการดำเนินการในขั้นตอนและได้รับมันsu output and input streamแล้วส่งผ่านid\n (ป้อน)ใน ouputstream และเขียนเพื่อส่งออกกระบวนการหากจะได้รับที่มี InputStream uid=0, คุณเป็นผู้ใช้ราก

ตอนนี้นี่คือตรรกะที่คุณจะใช้ในกระบวนการข้างต้น

เมื่อคุณได้รับ ouput สตรีมของกระบวนการผ่านคุณสั่ง (procrank, dumpsys meminfo ฯลฯ ... ) ด้วย\nแทนที่จะเป็น idและได้รับinputstreamและอ่านมันเก็บกระแสในไบต์ [], ถ่าน [] ฯลฯ ใช้ข้อมูลดิบ .. และคุณ เสร็จแล้ว!!!!!

การอนุญาต:

<uses-permission android:name="android.permission.FACTORY_TEST"/>

ตรวจสอบว่าคุณเป็นผู้ใช้รูทหรือไม่:

// su command to get root access
Process process = Runtime.getRuntime().exec("su");         
DataOutputStream dataOutputStream = 
                           new DataOutputStream(process.getOutputStream());
DataInputStream dataInputStream = 
                           new DataInputStream(process.getInputStream());
if (dataInputStream != null && dataOutputStream != null) {
   // write id to console with enter
   dataOutputStream.writeBytes("id\n");                   
   dataOutputStream.flush();
   String Uid = dataInputStream.readLine();
   // read output and check if uid is there
   if (Uid.contains("uid=0")) {                           
      // you are root user
   } 
}

ดำเนินการคำสั่งของคุณด้วย su

Process process = Runtime.getRuntime().exec("su");         
DataOutputStream dataOutputStream = 
                           new DataOutputStream(process.getOutputStream());
if (dataOutputStream != null) {
 // adb command
 dataOutputStream.writeBytes("procrank\n");             
 dataOutputStream.flush();
 BufferedInputStream bufferedInputStream = 
                     new BufferedInputStream(process.getInputStream());
 // this is important as it takes times to return to next line so wait
 // else you with get empty bytes in buffered stream 
 try {
       Thread.sleep(10000);
 } catch (InterruptedException e) {                     
       e.printStackTrace();
 }
 // read buffered stream into byte,char etc.
 byte[] bff = new byte[bufferedInputStream.available()];
 bufferedInputStream.read(bff);
 bufferedInputStream.close();
 }
}

logcat: ผลลัพธ์

คุณจะได้รับข้อมูลดิบในสายเดียวจากคอนโซลแทนในบางกรณีจาก API ใด ๆ ที่มีความซับซ้อนในการจัดเก็บที่คุณจะต้องแยกออกจากกันได้ด้วยตนเอง

นี่เป็นเพียงการลองโปรดแนะนำฉันหากฉันพลาดบางสิ่งบางอย่าง

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