Làm thế nào để sử dụng bộ nhớ hiện tại trong Android?


108

Tôi đã sử dụng / proc / meminfo và phản hồi lệnh đã phân tích cú pháp. Kết quả cho thấy rằng:

MemTotal: 94348 kB MemFree: 5784 kB

có nghĩa. nó cho thấy chỉ có 5MB bộ nhớ trống. Là nó có thể với điện thoại di động Android? Chỉ có 5-6 ứng dụng được cài đặt trên điện thoại di động của tôi và không có tác vụ nào khác đang chạy. nhưng lệnh này vẫn cho thấy có rất ít bộ nhớ trống.

Ai đó có thể làm rõ điều này? hoặc có cách nào khác để sử dụng bộ nhớ trong Android không?


2
Bạn đang cố gắng xem bộ nhớ trống trên mỗi thiết bị hay mỗi ứng dụng? Nếu mỗi ứng dụng, thì nó cần phải được tính toán trên heap a-la Debug.getNativeHeapFreeSize().
IgorGanapolsky

1
Để tính toán bộ nhớ trống (trong RAM) bằng / proc / meminfo, bạn phải lấy tổng hợp của MemFree , Buffers , CachedSwapCached . Có một API cho mục đích này do Android cung cấp, hoạt động trên API 16 và trên các phường. Meminfo rất hữu ích nếu bạn đang nhắm mục tiêu các API cũ hơn.
AB

Câu trả lời:


174

THẬN TRỌNG: Câu trả lời này đo mức sử dụng / khả dụng của bộ nhớ của THIẾT BỊ. Đây KHÔNG phải là những gì có sẵn cho ứng dụng của bạn. Để đo lường những gì APP của bạn đang làm và ĐƯỢC PHÉP thực hiện, Hãy sử dụng câu trả lời của nhà phát triển Android .


Tài liệu Android - ActivityManager.MemoryInfo

  1. lệnh parse / proc / meminfo. Bạn có thể tìm thấy mã tham chiếu tại đây: Nhận mức sử dụng bộ nhớ trong Android

  2. sử dụng mã dưới đây và nhận RAM hiện tại:

    MemoryInfo mi = new MemoryInfo();
    ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    activityManager.getMemoryInfo(mi);
    double availableMegs = mi.availMem / 0x100000L;
    
    //Percentage can be calculated for API 16+
    double percentAvail = mi.availMem / (double)mi.totalMem * 100.0;

Giải thích về số 0x100000L

1024 bytes      == 1 Kibibyte 
1024 Kibibyte   == 1 Mebibyte

1024 * 1024     == 1048576
1048576         == 0x100000

Rõ ràng là số được sử dụng để chuyển đổi từ byte sang mebibyte

PS: chúng ta chỉ cần tính tổng bộ nhớ một lần. vì vậy, chỉ gọi điểm 1 một lần trong mã của bạn và sau đó, bạn có thể gọi lại mã của điểm 2.


Tôi muốn kiểm tra dung lượng bộ nhớ. MemoryInfo là gì?
Piraba

PIraba, lớp API Android của nó. Kiểm tra nó tại đây developer.android.com/reference/android/app/… .
Badal

@SanjayJoshi Đó là vì biến availMem chứa bộ nhớ theo byte. 1024 Byte bằng 1 KiloByte và 1024 kilobyte bằng 1 MegaByte. Vì vậy, 1024 * 1024 bằng 1048576
Rolf ツ

2
Chuyển đổi thành double ở trên, nếu không thì phần trămAvail sẽ là 0
blueether

1
@Rolf ツ xin lỗi nhưng 1024 byte bằng một Kibibyte và 1024 Kibibyte là một MibiByte. Kilo và Mega là tiền tố thập phân. 1000 byte = 1 Kilobyte. Điều này cũng được giải thích sai trong câu trả lời.
JacksOnF1re

88

Nó phụ thuộc vào định nghĩa của bạn về truy vấn bộ nhớ mà bạn muốn lấy.


Thông thường, bạn muốn biết trạng thái của bộ nhớ heap, vì nếu nó sử dụng quá nhiều bộ nhớ, bạn sẽ nhận được OOM và làm hỏng ứng dụng.

Đối với điều này, bạn có thể kiểm tra các giá trị tiếp theo:

final Runtime runtime = Runtime.getRuntime();
final long usedMemInMB=(runtime.totalMemory() - runtime.freeMemory()) / 1048576L;
final long maxHeapSizeInMB=runtime.maxMemory() / 1048576L;
final long availHeapSizeInMB = maxHeapSizeInMB - usedMemInMB;

Biến "usedMemInMB" càng gần với "maxHeapSizeInMB", càng về gần availHeapSizeInMB0, bạn càng gần OOM. (Do phân mảnh bộ nhớ, bạn có thể nhận được OOM TRƯỚC khi con số này đạt đến 0.)

Đó cũng là những gì mà công cụ DDMS sử dụng bộ nhớ cho thấy.


Ngoài ra, còn có mức sử dụng RAM thực, là mức sử dụng của toàn bộ hệ thống - hãy xem câu trả lời được chấp nhận để tính toán điều đó.


Cập nhật: vì Android O làm cho ứng dụng của bạn cũng sử dụng RAM gốc (ít nhất là cho bộ nhớ Bitmap, thường là lý do chính cho việc sử dụng bộ nhớ lớn), và không chỉ heap, mọi thứ đã thay đổi và bạn nhận được ít OOM hơn (vì heap không chứa bitmap nữa, hãy kiểm tra tại đây ), nhưng bạn vẫn nên theo dõi việc sử dụng bộ nhớ nếu bạn nghi ngờ mình bị rò rỉ bộ nhớ. Trên Android O, nếu bạn bị rò rỉ bộ nhớ mà lẽ ra phải gây ra OOM trên các phiên bản cũ hơn, thì có vẻ như nó sẽ gặp sự cố mà bạn không thể bắt được. Đây là cách kiểm tra việc sử dụng bộ nhớ:

val nativeHeapSize = Debug.getNativeHeapSize()
val nativeHeapFreeSize = Debug.getNativeHeapFreeSize()
val usedMemInBytes = nativeHeapSize - nativeHeapFreeSize
val usedMemInPercentage = usedMemInBytes * 100 / nativeHeapSize

Nhưng tôi tin rằng tốt nhất có thể sử dụng trình biên dịch của IDE, trình biên dịch này hiển thị dữ liệu trong thời gian thực, sử dụng biểu đồ.

Vì vậy, tin tốt trên Android O là khó gặp sự cố hơn nhiều do OOM lưu trữ quá nhiều bitmap lớn, nhưng tin xấu là tôi không nghĩ có thể gặp trường hợp như vậy trong thời gian chạy.


CHỈNH SỬA: dường như Debug.getNativeHeapSize() thay đổi theo thời gian, vì nó hiển thị cho bạn tổng bộ nhớ tối đa cho ứng dụng của bạn. Vì vậy, các chức năng đó chỉ được sử dụng cho trình biên dịch, để hiển thị mức độ sử dụng ứng dụng của bạn.

Nếu bạn muốn nhận tổng số RAM thực và RAM gốc có sẵn, hãy sử dụng cái này:

val memoryInfo = ActivityManager.MemoryInfo()
(getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).getMemoryInfo(memoryInfo)
val nativeHeapSize = memoryInfo.totalMem
val nativeHeapFreeSize = memoryInfo.availMem
val usedMemInBytes = nativeHeapSize - nativeHeapFreeSize
val usedMemInPercentage = usedMemInBytes * 100 / nativeHeapSize
Log.d("AppLog", "total:${Formatter.formatFileSize(this, nativeHeapSize)} " +
        "free:${Formatter.formatFileSize(this, nativeHeapFreeSize)} " +
        "used:${Formatter.formatFileSize(this, usedMemInBytes)} ($usedMemInPercentage%)")

Chà. Rất đơn giản, nhưng rất đúng!
Ran

việc sử dụng bộ nhớ thực là gì? Vì vậy, usedMemInMB trong trường hợp này không phải là sử dụng bộ nhớ thực của ứng dụng? Khi tôi sử dụng mã này, nó hiển thị mức sử dụng giống như 50mb nhưng khi tôi vào cài đặt điện thoại và xem mức sử dụng bộ nhớ ở đó, ứng dụng của tôi hiển thị 100mb. tại sao có sự khác biệt này?
batmaci

1
@batmaci Bộ nhớ Heap chỉ là một phần của tổng mức sử dụng bộ nhớ của ứng dụng. Ngoài ra còn có việc sử dụng bộ nhớ gốc, thường được sử dụng cho các Trang web, trò chơi và một số mục đích nặng. Thông thường, các ứng dụng chỉ cần xem trên bộ nhớ heap, vì nó khá thấp so với RAM của thiết bị và nếu chúng đạt đến nó, ứng dụng sẽ bị lỗi (ngay cả khi có nhiều RAM trống).
nhà phát triển android

Đó là một đoạn mã hoàn hảo, rất hữu ích để kiểm tra OOM, cảm ơn rất nhiều.
aolphn

@AlphaOF Cảm ơn bạn, nhưng mọi thứ đã thay đổi trên Android O. Tôi đã cập nhật câu trả lời để phù hợp với tình hình ở đó.
nhà phát triển android

29

Đây là một cách để tính toán mức sử dụng bộ nhớ của ứng dụng hiện đang chạy :

public static long getUsedMemorySize() {

    long freeSize = 0L;
    long totalSize = 0L;
    long usedSize = -1L;
    try {
        Runtime info = Runtime.getRuntime();
        freeSize = info.freeMemory();
        totalSize = info.totalMemory();
        usedSize = totalSize - freeSize;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return usedSize;

}

4
Đây là một cách tiếp cận đơn giản, nhưng như nó đã được chỉ ra trong tài liệu, phương thức freeMemory () của lớp Runtime trả về bộ nhớ khả dụng cho chương trình hoặc ứng dụng hiện tại. Vì vậy, hãy lưu ý điều đó trong khi sử dụng.
Aksel Fatih

2
@Peter - Đúng, nó "sai" ở chỗ nó trả lời một câu hỏi khác với câu hỏi đã được hỏi. Mặt khác, điều này là "đúng" đối với những gì một nhà phát triển ứng dụng thường cần biết: nó hiếm khi quan trọng về trạng thái tổng thể của bộ nhớ trên THIẾT BỊ - nếu người dùng đã chạy nhiều ứng dụng, hệ điều hành sẽ tận dụng hầu hết bộ nhớ của nó - nếu không thì nó đang hoạt động kém hiệu quả. Hệ điều hành cần biết câu trả lời được chấp nhận đưa ra là gì, để biết khi nào bắt đầu giết các ứng dụng không được sử dụng gần đây. Nhưng một lập trình viên ứng dụng cần biết câu trả lời NÀY (và câu trả lời tương tự của nhà phát triển android) nói với bạn, so với runtime.maxMemory.
ToolmakerSteve

Các giải pháp này chỉ hoạt động trên bộ nhớ được Runtime tiếp xúc với ứng dụng. Điều này không cung cấp cái nhìn sâu sắc về toàn bộ bộ nhớ hệ thống như OP yêu cầu.
AB

Trên nhiều thiết bị (ví dụ như Xiaomi) Runtime.freeMemory()trả về 0 và chỉ Runtime.totalMemory()trả về bộ nhớ được cấp phát hiện tại.
artem

17

Một cách khác (hiện đang hiển thị 25MB trống trên G1 của tôi):

MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;

Này Alex, Cảm ơn rất nhiều vì sự giúp đỡ của bạn! 1 câu hỏi nữa. Mã này cung cấp cho tôi RAM khả dụng. Tôi cũng muốn hiển thị Tổng RAM. Làm thế nào để có được điều đó?
Badal

@Badal Tôi không biết một API Java cho việc đó. Bám sát vào phân tích cú pháp / proc / meminfo.
yanchenko

12

Triết lý quản lý bộ nhớ của Linux là "Bộ nhớ trống là bộ nhớ bị lãng phí".

Tôi giả định rằng hai dòng tiếp theo sẽ hiển thị bao nhiêu bộ nhớ trong "Bộ đệm" và bao nhiêu là "Bộ nhớ cache". Mặc dù có sự khác biệt giữa cả hai (vui lòng không hỏi sự khác biệt đó là gì :) cả hai đều gần như cộng thêm vào dung lượng bộ nhớ được sử dụng để lưu trữ dữ liệu tệp và siêu dữ liệu.

Một hướng dẫn hữu ích hơn nhiều để giải phóng bộ nhớ trên hệ thống Linux là free(1)lệnh; trên màn hình của tôi, nó báo cáo thông tin như sau:

$ miễn phí -m
             tổng số bộ đệm chia sẻ miễn phí đã sử dụng được lưu vào bộ nhớ đệm
Mem: 5980 1055 4924 0 91 374
- / + bộ đệm / bộ nhớ đệm: 589 5391
Hoán đổi: 6347 0 6347

Dòng +/- buffers / cache: là dòng kỳ diệu, nó báo cáo rằng tôi thực sự có khoảng 589 megs bộ nhớ xử lý được yêu cầu tích cực và khoảng 5391 megs bộ nhớ 'trống', theo nghĩa là 91 + 374 megabyte bộ đệm / bộ nhớ được lưu trong bộ nhớ đệm có thể bị vứt bỏ nếu bộ nhớ có thể được sử dụng ở nơi khác có lợi hơn.

(Máy của tôi đã hoạt động được khoảng ba giờ, gần như không làm được gì ngoài stackoverflow, đó là lý do tại sao tôi có rất nhiều bộ nhớ trống.)

Nếu Android không đi kèm free(1), bạn có thể tự tính toán với /proc/meminfotệp; Tôi chỉ thích free(1)định dạng đầu ra. :)


1
@Igor, sau đó bạn sẽ muốn cat /proc/meminfothay thế. Nó chi tiết hơn nhiều, nhưng MemFree. Buffers, và Cachedcó thể là những dòng quan trọng nhất.
sarnold

6

Tôi tham khảo một vài bài viết.

tài liệu tham khảo:

Phương thức getMemorySize () này được trả về MemorySize có tổng dung lượng bộ nhớ trống và tổng.
Tôi không tin hoàn toàn mã này.
Mã này đang thử nghiệm trên LG G3 cat.6 (v5.0.1)

    private MemorySize getMemorySize() {
        final Pattern PATTERN = Pattern.compile("([a-zA-Z]+):\\s*(\\d+)");

        MemorySize result = new MemorySize();
        String line;
        try {
            RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r");
            while ((line = reader.readLine()) != null) {
                Matcher m = PATTERN.matcher(line);
                if (m.find()) {
                    String name = m.group(1);
                    String size = m.group(2);

                    if (name.equalsIgnoreCase("MemTotal")) {
                        result.total = Long.parseLong(size);
                    } else if (name.equalsIgnoreCase("MemFree") || name.equalsIgnoreCase("Buffers") ||
                            name.equalsIgnoreCase("Cached") || name.equalsIgnoreCase("SwapFree")) {
                        result.free += Long.parseLong(size);
                    }
                }
            }
            reader.close();

            result.total *= 1024;
            result.free *= 1024;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }

    private static class MemorySize {
        public long total = 0;
        public long free = 0;
    }

Tôi biết rằng Pattern.compile () có giá đắt nên Bạn có thể chuyển mã của nó đến thành viên lớp.


3

Tôi đã xem qua Cây nguồn Android.

Bên trong com.android.server.am. ActivityManagerService.java (dịch vụ nội bộ do android.app hiển thị. ActivityManager ).

public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
    final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ);
    final long hiddenAppMem = mProcessList.getMemLevel(ProcessList.HIDDEN_APP_MIN_ADJ);
    outInfo.availMem = Process.getFreeMemory();
    outInfo.totalMem = Process.getTotalMemory();
    outInfo.threshold = homeAppMem;
    outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((hiddenAppMem-homeAppMem)/2));
    outInfo.hiddenAppThreshold = hiddenAppMem;
    outInfo.secondaryServerThreshold = mProcessList.getMemLevel(
            ProcessList.SERVICE_ADJ);
    outInfo.visibleAppThreshold = mProcessList.getMemLevel(
            ProcessList.VISIBLE_APP_ADJ);
    outInfo.foregroundAppThreshold = mProcessList.getMemLevel(
            ProcessList.FOREGROUND_APP_ADJ);
}

Bên trong android.os. Process.java

/** @hide */
public static final native long getFreeMemory();

/** @hide */
public static final native long getTotalMemory();

Nó gọi phương thức JNI từ android_util_Process.cpp

Phần kết luận

MemoryInfo.availMem = MemFree + Được lưu vào bộ nhớ đệm / proc / meminfo.

Ghi chú

Tổng bộ nhớ được thêm vào API cấp 16.


1

bạn cũng có thể sử dụng công cụ DDMS là một phần của SDK android. nó cũng giúp cấp phát bộ nhớ của mã java và mã c / c ++ gốc.


0
public static boolean isAppInLowMemory(Context context) {
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    activityManager.getMemoryInfo(memoryInfo);

    return memoryInfo.lowMemory;
}

0
final long usedMemInMB=(runtime.totalMemory() - runtime.freeMemory()) / 1048576L;
final long maxHeapSizeInMB=runtime.maxMemory() / 1048576L;
final long availHeapSizeInMB = maxHeapSizeInMB - usedMemInMB;

Đó là một mã kỳ lạ. Nó trả về MaxMemory - (totalMemory - freeMemory). Nếu freeMemory bằng 0, thì mã sẽ trả về MaxMemory - totalMemory, vì vậy nó có thể nhiều hơn hoặc bằng 0. Tại sao freeMemory không được sử dụng?


0

Đây là một cách khác để xem mức sử dụng bộ nhớ của ứng dụng:

adb shell dumpsys meminfo <com.package.name> -d

Đầu ra mẫu:

Applications Memory Usage (kB):
Uptime: 2896577 Realtime: 2896577

** MEMINFO in pid 2094 [com.package.name] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     3472     3444        0        0     5348     4605      102
  Dalvik Heap     2349     2188        0        0     4640     4486      154
 Dalvik Other     1560     1392        0        0
        Stack      772      772        0        0
    Other dev        4        0        4        0
     .so mmap     2749     1040     1220        0
    .jar mmap        1        0        0        0
    .apk mmap      218        0       32        0
    .ttf mmap       38        0        4        0
    .dex mmap     3161       80     2564        0
   Other mmap        9        4        0        0
      Unknown       76       76        0        0
        TOTAL    14409     8996     3824        0     9988     9091      256

 Objects
               Views:       30         ViewRootImpl:        2
         AppContexts:        4           Activities:        2
              Assets:        2        AssetManagers:        2
       Local Binders:       17        Proxy Binders:       21
    Death Recipients:        7
     OpenSSL Sockets:        0

 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

Để sử dụng bộ nhớ tổng thể:

adb shell dumpsys meminfo

https://developer.android.com/studio/command-line/dumpsys#meminfo

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.