精华内容
下载资源
问答
  • 创建UpCatcher是为了解决Android应用虚拟内存需求。 像“共享首选项”一样使用它,不同之处在于仅当系统内存至关重要时,它将对象转换为json并写入外部存储。 其余时间它将用作HashMap 。 两个简单的功能; ...
  • android 内存使用详情查询的几种方法

    千次阅读 2018-07-18 11:02:22
    android /proc/ 目录下为我们提供了操作系统几乎所有的状态信息,当然也包含系统的内存使用信息,下面列举了一些对应内存使用情况的目录信息: /proc/meminfo 机器的内存使用情况 /proc/pid/maps pid 为进程号,...

    一. /proc/meminfo

    android /proc/ 目录下为我们提供了操作系统几乎所有的状态信息,当然也包含系统的内存使用信息,下面列举了一些对应内存使用情况的目录信息:

    /proc/meminfo           机器的内存使用情况
    /proc/pid/maps          pid 为进程号,显示当前进程所长用的虚拟地址
    cat /proc/pid/statm     pid 为进程号,第二列为正在使用的物理内存大小
    小扩展

    /proc 目录是一个虚拟的目录,其下面的文件和目录也都是虚拟的,不占用实际的存储空间,而是存在于系统内存之中。proc 以文件系统的方式为访问系统内核的操作提供接口,它是动态从系统内核中读出所需的信息。

    => cat /proc/meminfo

    参数官方描述

    ==> 注意单位为 kB,下面列举几种常见项的意义

    rk3288:/ # cat /proc/meminfo
    MemTotal:        2045192 kB
    MemFree:          561972 kB 
    MemAvailable:    1360216 kB     
    Buffers:            2480 kB
    Cached:          1093140 kB
    SwapCached:            0 kB
    Active:           494260 kB
    Inactive:         814140 kB
    Active(anon):     214588 kB
    Inactive(anon):   219172 kB
    Active(file):     279672 kB
    Inactive(file):   594968 kB
    Unevictable:         256 kB
    Mlocked:             256 kB
    HighTotal:       1564668 kB
    HighFree:         443576 kB
    LowTotal:         480524 kB
    LowFree:          118396 kB
    SwapTotal:       1022260 kB
    SwapFree:        1022260 kB
    Dirty:               132 kB
    Writeback:             0 kB
    AnonPages:        213064 kB
    Mapped:           542300 kB
    Shmem:            221004 kB
    Slab:              89472 kB
    SReclaimable:      61508 kB
    SUnreclaim:        27964 kB
    KernelStack:        7248 kB
    PageTables:        17176 kB
    NFS_Unstable:          0 kB
    Bounce:                0 kB
    WritebackTmp:          0 kB
    CommitLimit:     2044856 kB
    Committed_AS:   32299816 kB
    VmallocTotal:     499712 kB
    VmallocUsed:           0 kB
    VmallocChunk:          0 kB
    CmaTotal:          16384 kB
    CmaFree:           15064 kB
    1. MemTotal:内存总数

    系统从加电开始到引导完成,BIOS等要保留一些内存,内核要保留一些内存,最后剩下可供系统支配的内存就是MemTotal。这个值在系统运行期间一般是固定不变的。

    2. MemFree:空闲内存数

    表示系统尚未使用的内存,MemUsed=MemTotal-MemFree 就是已被用掉的内存。

    3. MemAvailable:可用内存数

    应用程序可用内存数,系统中有些内存虽然已被使用但是可以回收的,比如 cache/buffer、slab 都有一部分可以回收,所以 MemFree 不能代表全部可用的内存,这部分可回收的内存加上 MemFree 才是系统可用的内存,即:MemAvailable≈MemFree+Buffers+Cached

    它是内核使用特定的算法计算出来的,是一个估计值。它与MemFree的关键区别点在于,MemFree是说的系统层面,MemAvailable是说的应用程序层面。

    4. Buffer:缓冲区内存数,用来给文件做缓冲大小
    5. Cache:缓存区内存数,用于高速缓存储器
    6. Active:最近常被使用的内存数
    7. Inative:不常被使用的内存数,很容易被系统移做他用
    8. slab:内核数据结构缓存的大小,可以减少申请和释放内存带来的消耗
    9. SReclaimable: 可收回 Slab 的大小
    10. SUnreclaim:不可收回 Slab 的大小(SUnreclaim+SReclaimable=Slab)
    11. HightTotal:RAM 中高地址物理内存总和,只能被用户空间程序使用
    12. LowTotal:RAM 中内核和用户空间程序都可以使用的内存总和(对于 512M 的 RAM: lowTotal = MemTotal)

    二. $ free 命令

    free 命令显示系统使用和空闲的内存情况,包括物理内存、交互区内存(swap)和内核缓冲区内存。

    rk3288:/ # free
                    total        used        free      shared     buffers
    Mem:       2094276608  1672122368   422154240   229789696     2912256
    -/+ buffers/cache:     1669210112   425066496
    Swap:      1046794240       90112  1046704128
    第一部分 Mem 行解释:
    1. total:内存总数
    2. used:已经使用的内存数
    3. free:空闲的内存数
    4. shared:多个进程共享的内存数
    5. buffers:缓存区内存数
    
    第二部分(-/+ buffers/cache)行解释:
    第二行可以理解成跟上面第一行的 total、used、free 这一些不对应,
    一共两个值,第一个是 (-buffers/cache),另一个是 (+buffer/cache)的值
    
    第一个值 (-buffers/cache):
    数值为:(Mem)used - (Mem)buffers
    含义为:应用程序真正使用的内存数,即所有应用程序已经使用的内存减去共享的内存数
    
    第二个值 (+buffer/cache):
    数值为:(Mem)free + (Mem)buffer
    含义为:应用程序可使用到的内存数,即当前未使用的内存数加上共享的内存数
    
    第三部分是交互内存的数,也就是通常所说的虚拟空间

    图解

    三. $ procrant 命令

    Android procrank 是按照内存占用情况对进程进行排序。因为它需要遍历 /proc 下的所有进程获取内存占用情况,所以在运行时候需要有 root 权限。可用排序的有 VSS、RSS、PSS、USS。

    首先说明一下应用内存耗用的几个单词的含义:

    VSS- Virtual Set Size       虚拟耗用内存(包含共享库占用的内存) 
    RSS- Resident Set Size      实际使用物理内存(包含共享库占用的内存) 
    PSS- Proportional Set Size  实际使用的物理内存(比例分配共享库占用的内存)
        - PSS 与 RSS 的区别是按比例分配,也就是如果三个进程都使用了同一个共享库(占30页内存),
        那么 PSS 认为每个进程占10页内存
    USS- Unique Set Size        进程独占的物理内存(不包含共享库占用的内存)
        - USS 是非常有用的数据,因为它反映了运行一个特定进程真实的成本(增量成本)。
        当一个进程被销毁后,USS 是真实返回给系统的内存。
        当进程中存在一个可疑的内存泄露时,USS 是最佳观察数据。
    
    一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS

    image
    image
    image
    image

    procrank 默认是按照 PSS 降序排列:

    rk3288:/ # procrank -h
    Usage: procrank [ -W ] [ -v | -r | -p | -u | -s | -h ]
        -v  Sort by VSS.
        -r  Sort by RSS.
        -p  Sort by PSS.
        -u  Sort by USS.
        -s  Sort by swap.
            (Default sort order is PSS.)
        -R  Reverse sort order (default is descending).
        -c  Only show cached (storage backed) pages
        -C  Only show non-cached (ram/swap backed) pages
        -k  Only show pages collapsed by KSM
        -w  Display statistics for working set only.
        -W  Reset working set of all processes.
        -o  Show and sort by oom score against lowmemorykiller thresholds.
        -h  Display this help screen.

    运行如下截图:

    rk3288:/ # procrank
      PID       Vss      Rss      Pss      Uss     Swap    PSwap    USwap    ZSwap  cmdline
      444  1753072K  184792K   81893K   70136K      12K       0K       0K       0K  system_server
      939  1848736K  210904K   80151K   42500K      16K       0K       0K       0K  com.google.android.gms.persistent
     1123  1966424K  203472K   73869K   36412K      16K       0K       0K       0K  com.google.android.gms
      569  1743596K  170144K   62840K   50472K      16K       0K       0K       0K  com.android.systemui
     1169  1772968K  171796K   62526K   38948K      16K       0K       0K       0K  com.google.android.googlequicksearchbox:search
      547  1697384K  121448K   34972K   27716K      16K       0K       0K       0K  com.google.android.inputmethod.latin
     1047  1714948K  137648K   32207K   18104K      16K       0K       0K       0K  com.android.launcher3
      325  1560208K  118160K   26989K   15632K      32K      16K      16K      15K  zygote
    10719  1697540K   97676K   24332K   19272K      16K       0K       0K       0K  com.android.vending
    10847  1813588K  126940K   23057K    4188K      16K       0K       0K       0K  com.google.android.gms.unstable
      971  1725516K  105736K   22103K    3280K      16K       0K       0K       0K  com.google.android.googlequicksearchbox:interactor
      626  1661076K   95856K   17894K   11976K      16K       0K       0K       0K  com.android.phone
     2538  1650844K   84140K   10332K    5172K      16K       0K       0K       0K  com.google.android.setupwizard

    四. dumpsys meminfo

    Android 提供的 dumpsys 工具可以用于查看感兴趣的系统服务信息与状态,可以通过下面的命令查看本设备所支持查看的所有 service 信息

    dumpsys | grep "DUMP OF SERVICE"
    DUMP OF SERVICE mount:
    DUMP OF SERVICE netd:
    DUMP OF SERVICE netd_listener:
    DUMP OF SERVICE netpolicy:
    ...
    dumpsys 具体命令查看帮助

    dumpsys 支持的 service 非常多,可以通过 -h 查看相关的 service 帮助信息,以 meminfo 为例演示:

    rk3288:/ # dumpsys meminfo -h
    meminfo dump options: [-a] [-d] [-c] [-s] [--oom] [process]
      -a: include all available information for each process.
      -d: include dalvik details.
      -c: dump in a compact machine-parseable representation.
      -s: dump only summary of application memory usage.
      -S: dump also SwapPss.
      --oom: only show processes organized by oom adj.
      --local: only collect details locally, don't call process.
      --package: interpret process arg as package, dumping all
                 processes that have loaded that package.
      --checkin: dump data for a checkin
    If [process] is specified it can be the name or
    pid of a specific process to dump.
    dumpsys meminfo 项意义

    dumpsys meminfo 后面可以加单个进程名查看某进程的内存耗用信息

    rk3288:/ # dumpsys meminfo com.android.launcher3
    Applications Memory Usage (in Kilobytes):
    Uptime: 18025666 Realtime: 22799195
    
    ** MEMINFO in pid 1047 [com.android.launcher3] **
                       Pss  Private  Private  SwapPss     Heap     Heap     Heap
                     Total    Dirty    Clean    Dirty     Size    Alloc     Free
                    ------   ------   ------   ------   ------   ------   ------
      Native Heap     9541     9408        0        0    14336    10830     3505
      Dalvik Heap     1875     1828        0        0     5102     2551     2551
     Dalvik Other      554      552        0        0
            Stack       36       36        0        0
           Ashmem        2        0        0        0
        Other dev       58        0       56        0
         .so mmap     4711      236     1556        0
        .apk mmap     5792        0      104        0
        .ttf mmap      296        0       80        0
        .dex mmap     3480        4     1908        0
        .oat mmap     2174        0        0        0
        .art mmap      875      520        4        0
       Other mmap      436        4        0        0
          Unknown      614      604        0        0
            TOTAL    30444    13192     3708        0    19438    13381     6056
    
     App Summary
                           Pss(KB)
                            ------
               Java Heap:     2352
             Native Heap:     9408
                    Code:     3888
                   Stack:       36
                Graphics:        0
           Private Other:     1216
                  System:    13544
    
                   TOTAL:    30444       TOTAL SWAP PSS:        0
    
     Objects
                   Views:      113         ViewRootImpl:        1
             AppContexts:       10           Activities:        1
                  Assets:        6        AssetManagers:        9
           Local Binders:       27        Proxy Binders:       40
           Parcel memory:       33         Parcel count:       51
        Death Recipients:        2      OpenSSL Sockets:        0
                WebViews:        0
    
     SQL
             MEMORY_USED:      963
      PAGECACHE_OVERFLOW:      550          MALLOC_SIZE:      117
    
     DATABASES
          pgsz     dbsz   Lookaside(b)          cache  Dbname
             4       60             73         7/29/6  /data/user/0/com.android.launcher3/databases/launcher.db
             4      456             60        88/28/5  /data/user/0/com.android.launcher3/databases/app_icons.db
             4       20             37         2/26/3  /data/user/0/com.android.launcher3/databases/widgetpreviews.db
    Native heap 和 Dalvik heap 的区别
    比较简单的理解是:
     C/C++ 申请的内存空间在 native heap 中,而 java 申请的内存空间则在 dalvik heap  中。
    
     dalvik heap 是 dalvik 虚拟机分配的内存,因为每一个应用都有一个虚拟机实例。

    项解释如下:

    几个概念解释:
    - Pss
    表示进程占用的实际内存,将跨进程共享页也加进来,进行比例计算 Pss。
    
    - Dirty 与 clean
    进程独占内存,也就是进程销毁时可以回收的内存容量。
    通常 Private Dirty 内存是最重要的部分,因为只被自己进程使用。Dirty内存是已经被修改的内存页,因此必须常驻内存
    
    * .so mmap & .dex mmap ... mmap 
    映射本地或虚拟机代码到使用的内存中。
    * Unknown 
    无法归类的其他项。主要包括大部分的本地分配。
    * Native Heap native
    代码申请的内存, 堆和栈,及静态代码块等。
    * TOTAL
    进程总使用的实际内存。
    *Objects 
    显示持有对象的个数。这些数据也是分析内存泄漏的重要数据,如 activity
    判断应用内存泄漏

    可以通过不断查看应用进程的 native heap 和 dalvik heap szie 值,如果这两个值不断增大,则说明可能存在未释放内存的情况。

    展开全文
  • 查看Linux & Android内存占用方法

    千次阅读 2013-10-12 13:59:27
    1. procrank (only for Android) 它从/proc/pid/maps中读取信息来进行统计。...• VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存) • RSS - Resident Set Size 实际使用物理内存(包含共享库

    1. procrank (only for Android)

    它从/proc/pid/maps中读取信息来进行统计。源码位于:/system/extras/procrank

    内存耗用:VSS/RSS/PSS/USS
    • VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
    • RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
    • PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
    • USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)

    2. cat /proc/pid/status

    VmPeak:     表示进程所占用最大虚拟内存大小
    VmSize:      表示进程当前虚拟内存大小
    VmLck:       表示被锁定的内存大小
    VmHWM:    表示进程所占用物理内存的峰值
    VmRSS:     表示进程当前占用物理内存的大小(与procrank中的RSS)
    VmData:     表示进程数据段的大小
    VmStk:       表示进程堆栈段的大小
    VmExe:      表示进程代码的大小
    VmLib:       表示进程所使用共享库的大小
    VmPTE:      表示进程页表项的大小

     

    3. 举例

    1. shell@android:/ $ procrank                                                       
    2.   PID    Vss       Rss      Pss      Uss  cmdline  
    3. 16044  247156K   94580K   81361K   79708K  com.android.pingpang  
    4. 16698  242440K   66436K   45516K   42064K  com.android.yujia  
    5.   
    6. shell@android:/ $ cat /proc/16044/status      
    7. VmPeak:   703476 kB  
    8. VmSize:   550940 kB  
    9. VmLck:         0 kB  
    10. VmHWM:    101500 kB  
    11. VmRSS:     94140 kB  
    12. VmData:   102016 kB  
    13. VmStk:       136 kB  
    14. VmExe:         8 kB  
    15. VmLib:     37968 kB  
    16. VmPTE:       346 kB  
    17. VmSwap:        0 kB  
    18. Threads:    22  
    19.   
    20. shell@android:/ $ cat /proc/16698/status                                         
    21. VmPeak:   693460 kB  
    22. VmSize:   516736 kB  
    23. VmLck:         0 kB  
    24. VmHWM:     71204 kB  
    25. VmRSS:     66060 kB  
    26. VmData:    58960 kB  
    27. VmStk:       136 kB  
    28. VmExe:         8 kB  
    29. VmLib:     46568 kB  
    30. VmPTE:       344 kB  
    31. VmSwap:        0 kB  
    32. Threads:    26 

    查看基于Android 系统单个进程内存、CPU使用情况的几种方法

    分类: Linux Kernel Android系统 554人阅读 评论(0) 收藏 举报
     一、利用Android API函数查看
    1.1 ActivityManager查看可用内存。
    ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo(); 
    am.getMemoryInfo(outInfo); 
    outInfo.availMem即为可用空闲内存。
    1.2、android.os.Debug查询PSS,VSS,USS等单个进程使用内存信息
    MemoryInfo[] memoryInfoArray = am.getProcessMemoryInfo(pids); 
    MemoryInfo pidMemoryInfo=memoryInfoArray[0];
    pidMemoryInfo.getTotalPrivateDirty();

    getTotalPrivateDirty()
    Return total private dirty memory usage in kB. USS

    getTotalPss()
    Return total PSS memory usage in kB. 
    PSS
    getTotalSharedDirty()
    Return total shared dirty memory usage in kB. RSS


    二、直接对Android文件进行解析查询
    /proc/cpuinfo系统CPU的类型等多种信息。
    /proc/meminfo 系统内存使用信息

    /proc/meminfo
    MemTotal: 16344972 kB
    MemFree: 13634064 kB
    Buffers: 3656 kB
    Cached: 1195708 kB
    我们查看机器内存时,会发现MemFree的值很小。这主要是因为,在linux中有这么一种思想,内存不用白不用,因此它尽可能的cache和buffer一些数据,以方便下次使用。但实际上这些内存也是可以立刻拿来使用的。
    所以 空闲内存=free+buffers+cached=total-used
    通过读取文件/proc/meminfo的信息获取Memory的总量。
    ActivityManager. getMemoryInfo(ActivityManager.MemoryInfo)获取当前的可用Memory量。

     

    三、通过Android系统提供的Runtime类,执行adb 命令(top,procrank,ps...等命令)查询
    通过对执行结果的标准控制台输出进行解析。这样大大的扩展了Android查询功能.例如:
    final Process m_process = Runtime.getRuntime().exec("/system/bin/top -n 1");
    final StringBuilder sbread = new StringBuilder();
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(m_process.getInputStream()), 8192);

    # procrank
    Runtime.getRuntime().exec("/system/xbin/procrank");
    内存耗用:VSS/RSS/PSS/USS
    Terms
    • VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
    • RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
    • PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
    • USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
    一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS
    USS is the total private memory for a process, i.e. that memory that is completely unique to that process.USS is an extremely useful number because it indicates the true incremental cost of running a particular process. When a process is killed, the USS is the total memory that is actually returned to the system. USS is the best number to watch when initially suspicious of memory leaks in a process.

     

    四、dumpsys

    dumpsys meminfo                                               
    Applications Memory Usage (kB):
    Uptime: 1031937 Realtime: 1167591179860

    Total PSS by process:
        44049 kB: com.skyworth.launchersky_app_home (pid 911)
        16839 kB: system (pid 791)
        12835 kB: com.skyworth.standardservices (pid 1310)
        11233 kB: com.android.wallpaper (pid 881)
         9791 kB: com.skyworth.sky_app_atv (pid 1018)
         9782 kB: android.process.media (pid 1232)
         9622 kB: com.skyworth.hotkey (pid 1666)
         9279 kB: com.android.systemui (pid 866)
         7400 kB: com.android.email (pid 1265)
         7318 kB: com.mstar.tv.service (pid 1246)
         6980 kB: com.skyworthdigital.stb.dataprovider (pid 1335)
         5808 kB: com.android.exchange (pid 1286)
         4923 kB: com.android.inputmethod.pinyin (pid 892)
         4351 kB: com.android.providers.calendar (pid 985)
         4132 kB: com.android.calendar (pid 961)
         3548 kB: com.android.deskclock (pid 1059)

    Total PSS by OOM adjustment:
        16839 kB: System
                   16839 kB: system (pid 791)
         9279 kB: Persistent
                    9279 kB: com.android.systemui (pid 866)
        44049 kB: Foreground
                   44049 kB: com.skyworth.launchersky_app_home (pid 911)
        11233 kB: Visible
                   11233 kB: com.android.wallpaper (pid 881)
        25076 kB: Perceptible
                   12835 kB: com.skyworth.standardservices (pid 1310)
                    7318 kB: com.mstar.tv.service (pid 1246)
                    4923 kB: com.android.inputmethod.pinyin (pid 892)
         6980 kB: A Services
                    6980 kB: com.skyworthdigital.stb.dataprovider (pid 1335)
         9791 kB: Previous
                    9791 kB: com.skyworth.sky_app_atv (pid 1018)
        44643 kB: Background
                    9782 kB: android.process.media (pid 1232)
                    9622 kB: com.skyworth.hotkey (pid 1666)
                    7400 kB: com.android.email (pid 1265)
                    5808 kB: com.android.exchange (pid 1286)
                    4351 kB: com.android.providers.calendar (pid 985)
                    4132 kB: com.android.calendar (pid 961)
                    3548 kB: com.android.deskclock (pid 1059)

    Total PSS by category:
        56161 kB: Dalvik
        30951 kB: Native
        28795 kB: Unknown
        24122 kB: .so mmap
        18489 kB: .dex mmap
         7047 kB: Other mmap
         1109 kB: .ttf mmap
         1036 kB: .apk mmap
           88 kB: Other dev
           52 kB: Ashmem
           24 kB: .jar mmap
           16 kB: Cursor

    Total PSS: 167890 kB

    展开全文
  • Android 处理内存泄露的方法

    千次阅读 2015-03-26 14:46:30
    1. 内容 本文档包含如下内容:   ...l 如何确定App存在内存泄露 ...l 如何定位App的内存...VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存) RSS - Resident Set Size 实际使用物理内存(包含共享

    1.   内容

    本文档包含如下内容:

     

    l  如何确定App存在内存泄露

    l  如何定位App的内存泄露位置

    l  怎样避免内存泄露

    2.   名词解释

    App:Application

    VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)

    RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)

    PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)

    USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)

    3.   Android查看内存的工具

    DDMS查看系统内存

    在sdk/ android-sdk_eng._linux-x86/tools下,启动ddms,

    ./ddms

    通过ddms的sysInfo,如下图,我们可以看到系统内存目前的分布情况,这是一个饼状图,

    从图中看BaiduReader大概占用了12%,10M左右的内存。

     

    使用procrank查看进程内存

    procrank 命令可以获得当前系统中各进程的内存使用快照,这里有PSS,USS,VSS,RSS。我们一般观察Uss来反映一个Process的内存使用情况,Uss 的大小代表了只属于本进程正在使用的内存大小,这些内存在此Process被杀掉之后,会被完整的回收掉,

    Vss和Rss对查看某一Process自身内存状况没有什么价值,因为他们包含了共享库的内存使用,而往往共享库的资源占用比重是很大的,这样就稀释了对Process自身创建内存波动。

    而Pss是按照比例将共享内存分割,某一Process对共享内存的占用情况。

    procrank 的代码在 /system/extras/procrank,,在模拟器或者设备上的运行文件位/system/xbin

    在adb shell之后,我们运行procrank下图是Help

    下图是BaiduReader运行下的所有进程的内存使用列表

    从上图我们可以看到,所有的后台守护进程都比基于dalvik的虚拟机进程要小的多,zygote是虚拟机收个进程,由它来负责folk生成其他的虚拟机进程,而刚才PSS中谈到的共享库,其实就是由Zygote加载的,而其他虚拟机进程与Zygote共享这些内存。

     

    使用脚本配合procrank跟踪内存变化(Linux 环境下面跑的内容)

    使用procrank来跟踪某进程的使用哪个情况我们常常借助与脚本。这样就可以查看某一段时间的内存变化。

    如创建一个文件:trackmem.sh    chmod 775 trackmem.sh

    内容如下:

    #!/bin/bash

     

    while true; do

    adb shell procrank | grep "com.baidu.BaiduReader"

    sleep 1

    done

    运行该脚本:

    ./trackmem.sh

     

             这个脚本的用途是每1秒钟让系统输出一次BaiduReader的内存使用状况,如下图:

    观察USS的变化,从7M多提高到了9M多,这是由于打开了一个比较消耗资源的阅读界面,之后的操作时,不断的重复打开关闭这个界面(Activity),会发现内存只会偶尔的下降一点,而不会跟随GC的回收策略,当Acitivity被关闭之后,相关的资源会一并回收,所以我们判断这个Activity很可能存在内存泄露。

     

    怎样判断是否存在内存泄露

    AndroidApp是基于虚拟机的,其内存管理都是由Dalvik代为管理的,GC的回收不是及时的,比如一个Activity被Finish掉之后,其内存的引用对象会在下次GC回收的时候,通过回收算法计算,如果这部分内存已经属于可回收的对象,那么这些垃圾对象会被一并回收,所以内存的趋势图大概如下:

     

     

    如果我们怀疑某一次操作或者某个界面存在内存泄露,一般的查找方法是重复这个操作,或者重复打开关闭这个界面,理论上,每次关闭都会对应一次大的内存释放,而如果存在内存泄露的情况,举例如下图,在重复打开关闭Reader的阅读界面的时候,内存一直在向上爬升,也就是说每次关闭这个Activity的时候,有些应该释放的内存没有被释放掉

     

     

     

     

     

     

     

     

     

     

     

    如何定位内存泄露的位置

    查找内存泄露一种比较土但比较彻底的方法就是代码走查,我们可以一行行的分析对象的创建去留等等,但会很耗时间,也比较迷茫

    这里给出一种通过工具来查找的方法,但此方法只适用于Java层的查找,C/C++是没用的,也就是说只针对与被虚拟机来管理的进程和内存。

           现在向大家引荐Eclipse Memory Analyzer tool(MAT),,可以直接使用RCP版本或者安装其eclipse的插件,下载地址是http://www.eclipse.org/mat/downloads.php 。

    Mat的解析文件是hprof文件。 这个文件存放了某Process的内存快照

    如何从手机或者模拟器获得hprof文件呢?

    adb shell

    #ps  (找一下要Kill的进程号)

    # chmod 777 /data/misc

    # kill -10 进程号

    这样会在/data/misc目录下生成一个带当前时间的hprof文件,比如

    heap-dump-tm1291023618-pid1059.hprof

    但是这个文件不能直接被mat读取,我们需要借助android提供的工具hprof-conv 来把上面的hprof转化为mat可以读取的格式。

    首先将文件pull到当前目录

    adb pull /data/misc/heap-dump-tm1291023618-pid1059.hprof ./

    然后借助hprof-conv转换一下格式,此工具在sdk/android-sdk_eng._linux-x86/tools下面.

    ./hprof-conv heap-dump-tm1291023618-pid1059.hprof readershot.hprof

     

    用mat或eclipse打开(如果装mat插件的话) ,选择[Leak Suspects Report],如图 :

    这样就Mat就会为我们自动生成一个泄露推测报告,如下图,

    从报告中报告的三个问题,我们大约可以断定这些地方存在一些问题,

    从上图中Suspect1中,可以看到由class loader加载的HashMap有内存聚集,大概分配了1.6M的内存,所以对照代码中的HashMapEntry,就可以准确定位到有可能存在内存泄露的地方,通过逻辑判断这部分是否有优化的可能。

    这里顺便介绍一下dalvik.system.PahtClassLoader,这个是Android中Dalvik的系统类和程序类的装载器,所有的.dex都需要通过它的装载之后生成我们所需要的对象。

     

     

    另外Mat还提供了其他的视图,比如上图可以通过类名/Class loadeer来展示各类所占用的堆空间大小,所占内存的比例,对象的数目,通过这些参数我们也可以判断哪些对象可能是不太正常的。

    简单介绍一下ShallowHeap和RetainedHeap。

    Shallow size就是对象本身占用内存的大小,不包含对其他对象的引用,也就是对象头加成员变量(不是成员变量的值)的总和。在32位系统上,对象头占用8字节,int占用4字节,不管成员变量(对象或数组)是否引用了其他对象(实例)或者赋值为null它始终占用4字节。

    Retained size是该对象自己的shallow size,加上从该对象能直接或间接访问到对象的shallow size之和。换句话说,retained size是该对象被GC之后所能回收到内存的总和。

     

     

    借助于Mat堆内存快照的分析,我们基本可以定位Java层的内存泄露的问题,Mat是个很强悍的工具,更多的用法请参考http://dev.eclipse.org/blogs/memoryanalyzer/

     

    而还有一些内存泄露通过Mat是查不出来的,比如native的代码,对C/C++是无能为力的,对于这些问题是本文无法涵盖的,相关可以参考valgrind(http://valgrind.org/

     

     

    如何避免内存泄露

    AndroidSDK中有一篇文章专门写了怎样避免内存泄露,这篇文章的中文翻译我贴在了下面。除了下文中提到的Context和View的强引用,还有一些需要注意点:

    1:BraodcastReceiver,ContentObserver,FileObserver在Activity onDeatory或者某类声明周期结束之后一定要unregister掉,否则这个Activity/类会被system强引用,不会被内存回收。

    2:不要直接对Activity进行直接引用作为成员变量,如果不得不这么做,请用private WeakReference<Activity> mActivity来做,相同的,对于Service等其他有自己声明周期的对象来说,直接引用都需要谨慎考虑是否会存在内存泄露的可能;

    3:很多内存泄露是由于循环引用造成的,比如a中包含了b,b包含了c,c又包含a,这样只要一个对象存在其他肯定会一直常驻内存,这要从逻辑上来分析是否需要这样的设计。

     

     

    下文来自http://androidappdocs.appspot.com/resources/articles/avoiding-memory-leaks.html

    Avoiding Memory Leaks

    避免内存泄露

             Android应用程序,至少是在 T-Mobile G1上,是被分配了16M的Heap。对于手机来说,这已经是很多内存了,但是对开发者而言,却显的很少。尽管你没有打算用光所有的内存,也应该尽量少用内存以至于其他应用程序不被杀掉。越多的应用程序被Android保存在内存里,用户在切换程序的时候就越快。作为我工作的一部分,我遇到的大部分 Android应用程序中的内存泄露问题都是因为相同的原因:对 Context保持一个长生命周期的引用。

             在Android里,一个Context被用于很多操作,但是大部分是用于加载和访问资源。这就是为什么所有的widget在他们的构造里都接收一个Context的参数。在一个典型的Android应用程序里,你经常用到两种Context,Activity 和Application。开发者经常把前者传到需要Context的类和方法里。

    @Override

    protected void onCreate(Bundle state) {

      super.onCreate(state);

      TextView label = new TextView(this);

      label.setText("Leaks are bad");

      setContentView(label);

    }

             这就意味views有一个对这个activity的引用,也就是保持了该Activity里的所有引用,经常是整个view体系和它所有的资源。因此如果你"泄露"了Context("泄露"意思是你保存了一个引用,因此阻止了GC收集它),你就泄露了很多内存。如果你不注意的话,泄露整个Activity真的很容易。

             当屏幕的orientation变化时,默认情况下系统会销毁当前的activity再创建一个保存原来状态的新activity,这时Android会从资源中重新加载这个application的UI。现在假设你写的一个application里有一个很大的bitmap,你又不想每次转屏都重新加载。最简单的方式就是把它保存为一个static变量:

    private static Drawable sBackground;

    @Override

    protected void onCreate(Bundle state) {

      super.onCreate(state);

      TextView label = new TextView(this);

      label.setText("Leaks are bad");

      if (sBackground == null) {

        sBackground = getDrawable(R.drawable.large_bitmap);

      }

      label.setBackgroundDrawable(sBackground);

      setContentView(label);

    }

             这个代码非常快,但是也是非常错误的,它泄露了屏幕旋转前的activity。当一个 Drawable附到一个view上时,view就被作为一个callback设置到drawable上。在上面一小断代码里,就意味着该drawable有一个对textview的引用,而这个textview又有对这个activity(就是这个context)的引用,而这个activity里有很多对其他对象的引用(取决你的代码)。

             这个例子是一个泄露Context的最简单的情况,你可以在 Home screen's source code(方法unbindDrawables())看到当一个activity被销毁时我们是怎么工作的,我们会设置保存drawable的callback为null。有很多情况可以造成一系列context泄漏,它们会很快地耗光你的内存,这些非常不好。

             有两个简单的方法来避免context相关的内存泄露。最明显的方法是避免context超过自己的使用范围。上面的例子表明对外部静态变量的引用同样危险。第二种解决方法是用Application context。这个context会存活在整个application生命周期中,它不依靠activity的生命周期。如果你想保存一个需要context的长生命周期的对象,记住使用Application context。你可以通过调用 Context.getApplicationContext() 或者Activity.getApplication()来获得它。

             总之,为了避免context相关的内存泄露,记得下面的步骤:

    不要在context-activity里保存长生命周期的引用 (对于activity的引用,应该有和这个activiy相同的生命周期)

    试着使用Application context来代替context-activity

    如果你不想控制非静态内部类的生命周期,就要避免在一个activity里使用它,而要用一个静态的内部类,对外部的这个activity有一个弱引用。这种解决方法有一个实例: ViewRoot和它的内部类中有一个对外部类的WeakReference

    GC对内存泄露是无能为力的。


    展开全文
  • Android内存泄露OOM的原因及解决方法

    千次阅读 2015-09-24 00:34:37
    在程序中,对内存使用超过一定的阀值就会导致内存溢出,而new出来的Object对象在使用完后触发GC也无法被回收 叫做内存泄漏 OOM的可能导致的现象? 1.程序卡顿,响应速度慢(内存占用高时JVM虚拟机会频繁触发GC) ...

    目录

    内存泄漏介绍

    导致内存泄漏(溢出)的原因有哪些?

    常见的内存泄漏案例分析


    内存泄漏介绍

    1.什么是OOM?

    OOM(out of memory)即内存溢出.在程序中,对内存使用超过一定的阀值就会导致内存溢出. 而当一个对象已经不需要在使用了,本该被回收,而另一个正在使用的对象持有它的引用,导致该对象不能被回收就产生了内存泄漏.内存泄露太多导致无法继续申请内存是导致OOM的主要原因之一.

    2.OOM导致的现象?

    1.程序卡顿,响应速度慢(内存占用高时JVM虚拟机会频繁触发GC)

    2.由于APP运行内存限制,会导致直接崩溃(OutOfMemoryError)

    3.触发Low Memory Killer机制,应用莫名被杀

    3.什么是内存抖动

    内存泄漏发生时的主要表现为内存抖动,可用内存慢慢变少,在Android studio中可以通过Android Profiler工具查看内存抖动情况

    堆内存都有一定的大小,能容纳的数据是有限制的,当Java堆的大小太大时,垃圾收集会启动停止堆中不再应用的对象,来释放内存。当在极短时间内分配给对象和回收对象的过程就是内存抖动。

    内存抖动一般是在循环语句中创建临时对象或在绘制时配置大量对象导致。 内存抖动会带来UI的卡顿,因为大量的对象创建,会很快消耗剩余内存,导致GC回收,GC会占用大量的帧绘制时间,从而导致UI卡顿

    导致内存泄漏(溢出)的原因有哪些?

    1. 创建的资源没有及时释放:

    如何避免:

    • 资源性对象及时关闭,使用的任何资源都要及时关闭或者异常处理,保证在最恶劣的情况下资源可以得到释放 (如:Cursor、File、Receiver、Sensor)

    • 资源的注册和反注册成对出现(广播,观察者) 如事件注册后未注销,会导致观察者列表中持有Context对象的引用

    • 页面退出时及时清理一些资源占用(集合对象,WebView) 容器中的对象在不用的时候及时清理,WebView存在着内存泄漏的问题,在应用中只要使用一次,WebView,内存就不会被释放掉.

    • 资源重复利用(使用adapter的时候使用convertView)

    2. 保存了耗用内存过大的对象(Bitmap)

    如何避免:

    • Bitmap没有使用的时候及时recycle释放内存

    • 对大图进行压缩,使用软引用或弱引用(使用这两种引用代码需要做不为空判断)

    • 使用缓存技术(LruCache和DiskLruCache)

    3.Static引用的资源 消耗过多的实例(Context的使用)

    如何避免:

    • 尽量避免static成员变量引用资源 消耗过多的实例,比如Context;静态变量不要持有大数据对象

    • 使用软引用代替强引用**

    • 尽量使用ApplicationContext,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题

    • 对于内部类尽量使用静态内部类,避免由于内部类导致的内存泄漏(静态内部类可以通过软引用使用外部的Context)如:Handler使用静态内部类

    4.线程生命周期不可控导致内存泄漏

    如何避免:

    将线程的内部类,改为静态内部类,在线程内部采用弱引用保存Context引用

    线程优化:避免程序中存在大量的Thread.可以使用线程池,并且页面退出时,终止线程.**

        例: 
        在activity中handler发一个延时任务,activity退出后,延迟任务的message还在主线程,它持有activity的handler引用,所以造成内存泄漏(handler非静态类,它会持有外部类的引用,也就是activity);
        这里可以把handler声明为static的,则handler的存活和activity生命周期无关了,如果handler内部使用外部类的非static对象(如:Context),应该通过弱引用传入,activity销毁时,移除looper线程中的消息.
    

    常见的内存泄漏案例分析

    1、单例模式引起的内存泄露

    由于单例模式的静态特性,使得它的生命周期和我们的应用一样长,如果让单例无限制的持有Activity的强引用就会导致内存泄漏

    内存泄漏代码片段:

    public class MyInstance {
        private static MyInstance mMyInstance;
        private Context mContext;
    
        private MyInstance(Context context) {
            this.mContext = context;
        }
        public static MyInstance getInstance(Context context) {
            if (mMyInstance == null) {
                synchronized (MyInstance.class) {
                    if (mMyInstance == null) {
                        mMyInstance = new MyInstance(context);
                    }
                }
            }
            return mMyInstance;
        }
    
        private View mView = null;
        public void setXXView(View xxView) {
            mView = xxView;
        }
    }
    

    解决方案:

    1. 传入的Context使用ApplicationContext;
    2. 将该属性的引用方式改为弱引用;
    public class MyInstance {
        private static MyInstance mMyInstance;
        private Context mContext;
    
        private MyInstance(Context context) {
            this.mContext = context.getApplicationContext();
        }
    
        public static MyInstance getInstance(Context context) {
            if (mMyInstance == null) {
                synchronized (MyInstance.class) {
                    if (mMyInstance == null) {
                        mMyInstance = new MyInstance(context);
                    }
                }
            }
            return mMyInstance;
        }
    
        private WeakReference<View> mView = null;
        public void setXXView(View xxView) {
            mView = new WeakReference<View>(xxView);
        }
    }
    

    2.Handler引发的内存泄漏

    内存泄漏代码片段:
    当Activity退出时,延时任务Message还在主线程的MessageQueue中等待,此时的Message持有Handler的强引用,并且Handler是Activity类的非静态内部类,所以也默认持有Activity的强引用.

        private final Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                // ...
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mHandler.sendMessageDelayed(Message.obtain(), 5000);
        }
    

    解决方案: 1.使用静态内部类,通过弱引用传入外部类的Context 2.在onDestroy中调用mHandler.removeCallbacksAndMessages(null)

        private final Handler mHandler = new MyHandler(this);
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mHandler.sendMessageDelayed(Message.obtain(), 5000);
        }
    
        static class MyHandler extends Handler {
            private SoftReference<Activity> reference;
    
            public MyHandler(Activity activity) {
                // 持有 Activity 的软引用
                reference = new SoftReference<Activity>(activity);
            }
    
            @Override
            public void handleMessage(Message msg) {
                Activity activity = reference.get();
                if (activity != null && !activity.isFinishing()) {
                    switch (msg.what) {
                        // 处理消息
                    }
                }
            }
        }
    

    4.内部类引起的内存泄漏

    内部类默认持有外部类强引用,容易出现内存泄漏

    内存泄漏代码片段:

        public void createNonStaticInnerClass(){
            CustomThread mCustomThread = new CustomThread();
            mCustomThread.start();
        }
        public class CustomThread extends Thread{
            @Override
            public void run() {
                super.run();
                while (true){
                    try {
                        Thread.sleep(5000);
                        Log.i(TAG,"CustomThread ------- 打印");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
    

    解决方案: 1.把线程类声明为静态的类,如果要用到Activity对象,那么就作为参数传入且为WeakReference 2.在Activity的onDestroy时,停止线程的执行

     public static class CustomThread extends Thread{
            private WeakReference<MainActivity> mActivity;
            public CustomThread(MainActivity activity){
                mActivity = new WeakReference<MainActivity>(activity)
            }
        }
    
    

    5.Activity Context 的不正确使用引起的内存泄漏

    使用ApplicationContext代替Activity Context ,因为ApplicationContext的生命周期也就是该应用生命周期,不依赖于activity的生命周期

    内存泄露的工具?

    1. MAT工具(很全面,但入手较难,MAT为Eclipse自带工具)
    2. Android Profiler(图像化工具,AndroidStudio自带工具)
    3. LeakCanary工具(简便)
        源码:https://github.com/square/leakcanary
         支持Eclipse的库:http://download.csdn.net/detail/ytuglt/9533490

    相关链接直达:

    Android APP性能优化之 ---- 布局优化(一)

    Android APP性能优化之 ---- 内存优化(二)

    Android APP性能优化之 ---- 代码优化(三)

    Android APP性能优化之 ---- 优化监测工具(四)

    Android APP性能优化之 ---- APK瘦身 App启动优化

    Android内存泄露OOM的原因及解决方法

    展开全文
  • 网上看到一位仁兄的这篇文章,写的很不错,摘抄下来备不时之需。... 名词解释 App:Application VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存) RSS - Resident Set Size 实际使用物理内存(...
  • android 内存简介

    2018-05-10 16:58:37
    以下简单介绍下android内存JAVA是在JVM所虚拟出的内存环境中运行的,内存分为三个区:堆、栈和方法区。栈(stack):是简单的数据结构,程序运行时系统自动分配,使用完毕后自动释放。优点:速度快。堆(heap):用于...
  • Android内存监控

    2018-02-24 14:09:23
    因为Android也是基于Linux所以同理 可以看VSS/RSS/PSS/USS另外可以用adb shell dumpsys meminfo processname的方式,这种方式是统计PSS,如果怀疑有memoryleak的话可以检测下native heap是否是持续增长,如果想检查...
  • 1.JAVA是在JVM所虚拟出的内存环境中运行的,内存分为三个区:堆、栈和方法区。 ①.栈(stack):是简单的数据结构,程序运行时系统自动分配,使用完毕后自动释放。优点:速度快。 ②.堆(heap):用于存放由new创建的...
  • JAVA 是在JVM所虚拟出的内存环境下运行的,内存分为三个区:堆、栈和方法区。 栈(stack):是简单的数据结构,程序运行时系统自动分配,使用完毕后自动释放。优点:速度快。 堆(heap):用于存放由new 创建的对象...
  • JAVA是在JVM所虚拟出的内存环境中运行的,内存分为三个区:堆、栈和方法区。栈(stack):是简单的数据结构,程序运行时系统自动分配,使用完毕后自动释放。优点:速度快。堆(heap):用于存放由new创建的对象和数组。...
  • android内存优化(3)

    2019-09-17 12:07:14
    其他小tips 对常量使用static final... 静态方法代替虚拟方法 减少不必要的全局变量 避免创建不必要的对象 避免内部Getters/Setters 避免使用浮点数 使用实体类比接口好 避免使用枚举 for循环 ...
  • JAVA是在JVM所虚拟出的内存环境中运行的,内存分为三个区:堆、栈和方法区。 栈(stack):是简单的数据结构,程序运行时系统自动分配,使用完毕后自动释放。优点:速度快。 堆(heap):用于存放由new创建的对象和数...
  • Android内存泄漏超级精炼详解

    千次阅读 2018-03-27 11:46:46
    JAVA是在JVM所虚拟出的内存环境中运行的,JVM的内存可分为三个区:堆(heap)、栈(stack)和方法区(method)。 栈(stack):是简单的数据结构,但在计算机中使用广泛。栈最显著的特征是:LIFO(Last In, First Out, ...
  • 静态方法代替虚拟方法 如果不需要访问某对象的字段,将方法设置为静态,调用会加速15%到20%。这也是一种好的做法,因为你可以从方法声明中看出调用该方法不需要更新此对象的状态。   减少不必要的全局变量 尽量...
  • 本文实例讲述了Android SQLite数据库操作方法。分享给大家供大家参考,具体如下: SQLite and Android SQLite简介 SQLite是一个非常流行的嵌入式数据库,它支持SQL语言,并且只利用很少的内存就有很好的性能。此外,...
  • JAVA是在JVM所虚拟出的内存环境中运行的,内存分为三个区:堆、栈和方法区。 栈(stack):是简单的数据结构,程序运行时系统自动分配,使用完毕后自动释放。优点:速度快。 堆(heap):用于存放由new创建的对象...
  • 查看指定进程的内存使用状态 $ procrank | grep name procrank命令输出说明: VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存 RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存) ...
  • 而且使用方法的时候,Android Studio 会有预览效果,如下图: 不过不用担心,只是预览效果,运行的时候只有下拉才会出现~ 3.方法三 Java代码设置 final RefreshLayout refreshLayout = (RefreshLayout) ...
  • 静态方法代替虚拟方法 减少不必要的全局变量 避免创建不必要的对象 避免内部Getters/Setters 避免使用浮点数 使用实体类比接口好 避免使用枚举 永远不要在for的第二个条件中...
  • android 挂载 SDcard 的方法

    千次阅读 2013-01-17 15:22:23
    Android模拟器或真机都会有一定大小的内部存储空间(不是指内存,指的是持久化存储空间),但这并不够,有时我们需要更大的存储空间。为了在模拟器上开发使用扩展存储空间的程序,需要在PC上模拟一个SDCard的虚拟...
  • MMKV的介绍MMKV 是基于...关于mmap内存映射mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后...
  • 不要做不必要的事情,2尽可能节省内存使用尽可能避免创建对象使用自身的方法,如string.indexOf(),String.lastIndexOf(),乘虚自身的方法使用虚拟优于使用接口。在嵌入式开发中,通过接口引用来调用会花费2倍于虚拟的...
  • 2.使用静态方法代替虚拟方法,比如不需要访问对象的字段时,将此方法设置为静态,这样调用这个方法时就不需要更新这个对象的状态; 3.将成员变量缓存到本地,因为访问对象的成员变量比访问本地变量慢得多;比如for...
  • 一、目标我们之前介绍过Unicorn来执行Android原生的so,Unicorn只是虚拟了cpu,执行纯算法的函数是足够用了,但是如果函数中含有系统调用之类的操作,Unicorn就无能为力了。本文介绍一个新朋友AndroidNativeEmu他模拟...
  • 件针对小内存使用做了 优化。同时虚拟机是基于寄存器的,所有的类都经由 JAVA 编译器编译,然后通过 SDK 中 的 "dx" 工具转化成.dex 格式由虚拟机执行。 Dalvik 虚拟机依赖于 linux 内核的一些功能,比如线程机制和...

空空如也

空空如也

1 2 3 4 5
收藏数 84
精华内容 33
关键字:

虚拟内存使用方法android