前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >APP性能测试—内存使用率

APP性能测试—内存使用率

作者头像
清风穆云
发布2021-08-09 11:32:53
3.9K0
发布2021-08-09 11:32:53
举报
文章被收录于专栏:QA一隅QA一隅

从操作系统的角度来说,内存就是一块数据存储区域,是可被操作系统调度的资源。在多任务(进程)的操作系统中,内存管理尤为重要,操作系统需要为每一个进程合理的分配内存资源。所以可以从操作系统对内存分配和回收两方面来理解内存管理机制。

  • 分配机制:为每一个任务(进程)分配一个合理大小的内存块,保证每一个进程能够正常的运行,同时确保进程不会占用太多的内存。
  • 回收机制:当系统内存不足的时候,需要有一个合理的回收再分配机制,以保证新的进程可以正常运行。

Android 内存管理

内存管理机制

Android系统是基于Linux 内核开发的开源操作系统,而linux系统的内存管理有其独特的动态存储管理机制。不过Android系统对Linux的内存管理机制进行了优化,Linux系统会在进程活动停止后就结束该进程,而Android把这些进程都保留在内存中,直到系统需要更多内存为止。

这些保留在内存中的进程通常情况下不会影响整体系统的运行速度,并且当用户再次激活这些进程时,提升了进程的启动速度。

分配机制

Android为每个进程分配内存的时候,采用了弹性的分配方式,也就是刚开始并不会一下分配很多内存给每个进程,而是给每一个进程分配一个“够用”的量。这个量是根据每一个设备实际的物理内存大小来决定的。

随着应用的运行,可能会发现当前的内存可能不够使用了,这时候Android又会为每个进程分配一些额外的内存大小。但是这些额外的大小并不是随意的,也是有限度的,系统不可能为每一个App分配无限大小的内存。

Android系统的宗旨是最大限度的让更多的进程存活在内存中,因为这样的话,下一次用户再启动应用,不需要重新创建进程,只需要恢复已有的进程就可以了,减少了应用的启动时间,提高了用户体验。

回收机制

Android对内存的使用方式是“尽最大限度的使用”,这一点继承了Linux的优点。Android会在内存中保存尽可能多的数据,即使有些进程不再使用了,但是它的数据还被存储在内存中,所以Android现在不推荐显式的“退出”应用。

因为这样,当用户下次再启动应用的时候,只需要恢复当前进程就可以了,不需要重新创建进程,这样就可以减少应用的启动时间。只有当Android系统发现内存不够使用,需要回收内存的时候,Android系统就会需要杀死其他进程,来回收足够的内存。但是Android也不是随便杀死一个进程,比如说一个正在与用户交互的进程,这种后果是可怕的。所以Android会有限清理那些已经不再使用的进程,以保证最小的副作用。

内存分类

Linux里面,一个进程占用的内存有不同种说法,有四种形式:

  • VSS- Virtual Set Size 虚拟耗用内存
  • RSS- Resident Set Size实际使用物理内存
  • PSS- Proportional Set Size 按比例使用的物理内存
  • USS- Unique Set Size 进程独自占用的物理内存
VSS

VSS是单个进程全部可访问的地址空间,其大小可能包括还尚未在内存中驻留的部分。对于确定单个进程实际内存使用大小,VSS用处不大。

RSS

RSS是单个进程实际占用的内存大小,RSS不太准确的地方在于它包括该进程所使用共享库全部内存大小。对于一个共享库,可能被多个进程使用,实际该共享库只会被装入内存一次。

PSS

PSS不同于RSS,它只是按比例包含其所使用的共享库大小。PSS相对于RSS计算共享库内存大小是按比例的。例如:3个进程使用同一个占用30个内存页的共享库。对于三个进程中的任何一个,PSS 将只包括10个内存页。 PSS 是一个非常有用的数字,因为系统中全部进程以整体的方式被统计, 对于系统中的整体内存使用是比较准确的统计。

USS

USS是单个进程私有的内存大小,即该进程独占的内存部分。USS揭示了运行一个特定进程在的真实内存增量大小。如果进程终止,USS就是实际被返还给系统的内存大小。

说明:

  • 一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS
  • 实际在统计查看某个进程内存占用情况的时候,看PSS是比较客观的

Android 内存测试

获取设备内存信息

Linux操作系统中,/proc是一个位于内存中的伪文件系统(in-memory pseudo-file system)。该目录下保存的不是真正的文件和目录,而是一些运行时信息,如系统内存、磁盘io、设备挂载信息和硬件配置信息等。

使用命令adb shell cat /proc/meminfo查看设备的整体内存使用情况。

代码语言:javascript
复制
adb shell cat /proc/meminfo
MemTotal:        3082716 kB
MemFree:         1804236 kB
MemAvailable:    2438240 kB
Buffers:           21552 kB
Cached:           752800 kB
SwapCached:            0 kB
Active:           825432 kB
Inactive:         344876 kB
Active(anon):     398388 kB
Inactive(anon):    47244 kB
Active(file):     427044 kB
Inactive(file):   297632 kB
Unevictable:         256 kB
Mlocked:             256 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:        396248 kB
Mapped:           432708 kB
Shmem:             49696 kB
Slab:              64600 kB
SReclaimable:      26192 kB
SUnreclaim:        38408 kB
KernelStack:       14336 kB
PageTables:        19680 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     1541356 kB
Committed_AS:   20566920 kB
VmallocTotal:   34359738367 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:       18368 kB
DirectMap2M:     3127296 kB

部分参数含义如下:

  • MemTotal: 表示可供系统支配的内存,系统从开机到加载完成,操作系统内核要保留一些内存,最后剩下可供系统支配的内存就是MemTotal
  • MemFree:表示系统尚未使用的内存。
  • MemAvailable:应用程序可用内存大小。

系统中有些内存虽然已被使用但是可以回收的,比如cache可以回收,所以MemFree不能代表全部可用的内存,这部分可回收的内存加上MemFree才是系统可用的内存,即:MemAvailable≈MemFree+系统回收内存,它是内核使用特定的算法计算出来的,是一个估计值。它与MemFree的关键区别点在于,MemFree是说的系统层面,MemAvailable是说的应用程序层面。

  • Cached: 缓冲区内存大小。
  • Buffers: 缓存区内存大小。
获取应用内存占用信息

连接设备,使用命令adb shell procrank来获取各个应用的VSS、RSS、PSS、USS

代码语言:javascript
复制
λ adb shell procrank
  PID       Vss      Rss      Pss      Uss  cmdline
 1730  2031892K  395740K  251241K  221764K  com.hunantv.imgo.activity
 4795  1653640K  261976K  140397K  119176K  com.tal.kaoyan
  694   975996K  187696K   85604K   76248K  com.android.systemui
  574  1308464K  178312K   77288K   67920K  system_server
 4915  1518732K  160100K   65918K   57488K  com.tal.kaoyan:pushservice
  806   929724K  142008K   44211K   36308K  com.android.settings
  292  1127072K  125732K   32235K   23864K  zygote
 1842   904940K  120480K   28330K   21852K  com.android.launcher3
 2588  1521168K  131268K   25032K   14032K  com.hunantv.imgo.activity:QS
  789   895800K  110356K   24897K   19572K  com.android.phone
 2378  1304108K  135616K   24510K   12020K  com.hunantv.imgo.activity:pushcore
 2318  1284692K  116828K   16963K    7500K  com.hunantv.imgo.activity:pushservice
  682   889216K   97264K   15347K   11120K  com.android.inputmethod.latin
 1278   874704K   94340K   14498K   10120K  android.process.acore
 4966   887688K   93944K   13354K    8856K  com.android.packageinstaller
  280   120504K   14336K   12390K   12352K  /system/bin/local_opengl
 4754  1282184K  105700K   11988K    4620K  com.hunantv.imgo.activity:ww
  986   874004K   83028K   10501K    7280K  com.android.deskclock
 4690  1199892K   76916K    9015K    6232K  com.android.gallery3d
  301    71636K   17780K    8707K    7900K  media.extractor
 1044   866616K   74928K    6947K    4128K  com.genymotion.genyd
 5078   872856K   78192K    6554K    2324K  com.android.webview:webview_service
 1032   867468K   73080K    6177K    3428K  com.genymotion.systempatcher
 4722   864988K   73320K    5588K    2788K  com.genymotion.superuser
 1656   864388K   74560K    5216K    2244K  com.android.defcontainer
  951   863916K   71788K    4867K    2056K  android.ext.services
 4706   863972K   70828K    4805K    2136K  com.android.musicfx
  302    78232K   14136K    4496K    3096K  /system/bin/mediaserver
 4737   863776K   69620K    4455K    1836K  com.svox.pico
  293    42380K   10328K    4098K    3708K  /system/bin/audioserver
获取指定包的内存占用情况

我们可以使用adb命令来测试指定进程包名的内存使用详细情况,命令格式如下:

代码语言:javascript
复制
adb shell dumpsys meminfo [pkg or pid]

命令执行之后如下所示

代码语言:javascript
复制
 λ adb shell dumpsys meminfo com.youku.phone
Applications Memory Usage (in Kilobytes):
Uptime: 1253283 Realtime: 1253283

** MEMINFO in pid 2040 [com.youku.phone] **
                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap   165059   165008        0        0   244480   207583    36896
  Dalvik Heap    83625    83428        0        0    95519    79135    16384
 Dalvik Other    10853    10852        0        0
        Stack      120      120        0        0
       Ashmem      600      144        0        0
    Other dev       53        0       28        0
     .so mmap    58881     3056    48540        0
    .jar mmap        6        0        4        0
    .apk mmap    23139      124    14948        0
    .ttf mmap      626        0      404        0
    .dex mmap    81423       28    42536        0
    .oat mmap     6730        0     1436        0
    .art mmap     2821     2516        0        0
   Other mmap     8932       12     6272        0
      Unknown    49054    49052        0        0
        TOTAL   491922   314340   114168        0   339999   286718    53280

 App Summary
                       Pss(KB)
                        ------
           Java Heap:    85944
         Native Heap:   165008
                Code:   111076
               Stack:      120
            Graphics:        0
       Private Other:    66360
              System:    63414

               TOTAL:   491922       TOTAL SWAP PSS:        0

 Objects
               Views:     2680         ViewRootImpl:        2
         AppContexts:       18           Activities:        2
              Assets:       16        AssetManagers:        4
       Local Binders:      134        Proxy Binders:       47
       Parcel memory:       62         Parcel count:      250
    Death Recipients:        1      OpenSSL Sockets:        4

 SQL
         MEMORY_USED:     1425
  PAGECACHE_OVERFLOW:      872          MALLOC_SIZE:     1120

 DATABASES
      pgsz     dbsz   Lookaside(b)          cache  Dbname
         4       32             14         0/17/1  /data/user/0/com.youku.phone/databases/video-download2.db
         4       32             79        10/19/7  /data/user/0/com.youku.phone/databases/video-download2.db (1)
         4       20             29         3/16/2  /data/user/0/com.youku.phone/databases/accs.db
         4       36             97         3/18/4  /data/user/0/com.youku.phone/databases/ut-abtest-v1.db
         4      308             18         1/15/2  /data/user/0/com.youku.phone/databases/data_cache.db
         4      308             50         2/15/3  /data/user/0/com.youku.phone/databases/data_cache.db (2)
         4      100             25         1/17/2  /data/user/0/com.youku.phone/databases/ut.db

 Asset Allocations
    zip:/data/app/com.youku.phone-1/base.apk:/assets/Trebuchet_MS_Bold.ttf: 7K
    zip:/data/app/com.youku.phone-1/base.apk:/assets/yk_iconfont.ttf: 12K
    zip:/data/app/com.youku.phone-1/base.apk:/assets/Trebuchet_MS_Bold.ttf: 7K
    zip:/data/app/com.youku.phone-1/base.apk:/assets/Trebuchet_MS_Bold.ttf: 7K
    zip:/data/app/com.youku.phone-1/base.apk:/assets/iconfont_detail_page.ttf: 2K
    zip:/data/app/com.youku.phone-1/base.apk:/assets/Trebuchet_MS_Bold.ttf: 7K
    zip:/data/app/com.youku.phone-1/base.apk:/assets/fonts/ykf_iconfont.ttf: 27K
    zip:/data/app/com.youku.phone-1/base.apk:/assets/fonts/new_danmaku_iconfont.ttf: 3K
    zip:/data/app/com.youku.phone-1/base.apk:/assets/player_icon_font/iconfont.ttf: 13K
重点关注参数

一般情况下横轴仅需关注Pss TotalPrivate Dirty列。 Private Dirty表示进程独占内存。

  • Native HeapNative代码分配的内存。native进程采用C/C++实现,不包含dalvik实例的linux进程,/system/bin/目录下面的程序文件运行后都是以native进程形式存在的.
  • Dalvik HeapJava对象分配的占据内存
其他参数
  • Dalvik Other:类数据结构和索引占据内存。
  • Stack:栈内存
  • Ashmem:不以dalvik- 开头的内存区域,匿名共享内存用来提供共享内存通过分配一个多个进程可以共享的带名称的内存块。匿名共享内存(Anonymous Shared Memory-AshmemAndroid匿名共享内存是基于Linux共享内存的,都是在tmpfs文件系统上新建文件,并将其映射到不同的进程空间,从而达到共享内存的目的,只是Android在Linux的基础上进行了改造,并借助Binder+fd文件描述符实现了共享内存的传递。
  • Other dev:内部driver占用的内存
  • .so mmap C库代码占用的内存
  • .jar mmap java文件代码占用的内存
  • .apk mmap apk代码占用的内存
  • .ttf mmap ttf文件代码占用的内存
  • .dex mmap dex文件代码占用内存。类函数的代码和常量占用的内存,dex mmap是映射classex.dex文件,Dalvik虚拟机从dex文件加载类信息和字符串常量等。Dex文件有索引区和Data
  • Other mmap 其它文件占用的内存

自动化获取性能数据

前面我们使用adb命令获取CPU,内存性能数据,但是如果想批量获取性能数据,使用命令一个个查询会非常的不方便,我们可以使用Python自动化代码来自动获取性能数据,代码实现如下:

代码语言:javascript
复制

import csv
import os
import time


class Monitoring(object):
    def __init__(self, count,pkg):
        self.pkg=pkg   #包名
        self.counter = count #统计次数
        self.cpudata = [("timestamp", "cpustatus")] #cpu性能数据
        self.memdata = [("timestamp", "memstatus")] #内存性能
        
        
    def getCurrentTime(self):
    '''获取当前的时间戳'''
        currentTime = time.strftime("%H:%M:%S", time.localtime())
        return currentTime


    def getCurrentDate(self):
        '''获取当前日期'''
        datetime=time.strftime("%Y-%m-%d %H_%M_%S")
        return datetime    
        

    def monitoring_cpu(self):
        '''cpu监控'''
        result = os.popen(" adb shell top -m 100 -n 1  -d 1 -s cpu | findstr " +str(self.pkg)) #获取cpu性能指标数据
        res=result.readline().split(" ") #根据返回数据进行分割
        print(res)

        if res==['']: # 返回数据为空时处理
            print('no data')
        else:
            cpuvalue=list(filter(None, res))[4]  #获取cpu数据
            currenttime = self.getCurrentTime()

            print("current time is:"+currenttime)
            print("cpu used is:" + cpuvalue)
            self.cpudata.append([currenttime, cpuvalue])

    def monitoring_memeroy(self):
        '''获取内存数据'''
        result = os.popen(" adb shell procrank | findstr " + str(self.pkg))  # 获取内存性能指标数据
        res = result.readline().split(" ")  # 根据返回数据进行分割
        print(res)

        mem_kb = list(filter(None, res))[3][:-1] #获取Pss值并去掉最后一个字符K
        mem_mb=round((float(mem_kb) / 1024), 2) #转化为MB

        currenttime = self.getCurrentTime()
        print("current time is:" + currenttime)
        print("memory used is:" + str(mem_mb))
        self.memdata.append([currenttime, mem_mb])


    def get_cpu_datas(self):
        '''连续获取cpu性能数据'''
        while self.counter > 0:
            self.monitoring_cpu()
            self.counter = self.counter - 1
            time.sleep(2)

    def get_memeroy_datas(self):
        '''连续获取内存性能数据'''
        while self.counter > 0:
            self.monitoring_memeroy()
            self.counter = self.counter - 1
            time.sleep(3)

    def SaveDataToCSV(self,data_type):
        '''
        存储性能测试数据
        :param data_type: 
        :return: 
        '''
        now=self.getCurrentDate()
        if data_type=='cpu':
            csvfile = open('./cpustatus_'+now+'.csv', 'w', encoding='utf8', newline='')
            writer = csv.writer(csvfile)
            writer.writerows(self.cpudata)
            csvfile.close()
        elif data_type=='mem':
            csvfile = open('./memstatus_' + now + '.csv', 'w', encoding='utf8', newline='')
            writer = csv.writer(csvfile)
            writer.writerows(self.memdata)
            csvfile.close()
        else:
            print('data_type error!')


if __name__ == '__main__':
    m = Monitoring(20,'com.youku.phone')
    m.get_cpu_datas()
    m.SaveDataToCSV('cpu')
    m.get_memeroy_datas()
    m.SaveDataToCSV('mem')

执行完成之后可以在在本地生成的csv文件查看到数据,然后生成图表即可。

  1. CPU数据
  1. 内存数据

内存泄漏

内存泄漏(Memory leak)是指由于疏忽或错误造成程序未能释放已经不再使用的内存。其实说白了就是内存空间使用完毕之后未回收。内存泄漏会因为减少可用内存的数量从而降低设备的性能。

Android 内存泄漏测试可以在APP中集成LeakCanary进行测试。

Android内存泄漏原因
使用static变量引起的内存泄漏

因为static变量的生命周期是在类加载时开始 类卸载时结束,也就是说static变量是在程序进程死亡时才释放,如果在static变量中引用了Activity那么这个Activity由于被引用,便会随static变量的生命周期一样,一直无法被释放,造成内存泄漏。

一般解决办法:想要避免context相关的内存泄漏,需要注意以下几点:

  • 不要对activitycontext长期引用(一个activity的引用的生存周期应该和activity的生命周期相同)
  • 如果可以的话,尽量使用关于applicationcontext来替代和activity相关的context
  • 如果一个acitivity的非静态内部类的生命周期不受控制,那么避免使用它;
线程引起的内存泄漏

Java中线程是垃圾回收机制的根源,也就是说,在运行系统中DVM虚拟机总会使硬件持有所有运行状态的进程的引用,结果导致处于运行状态的线程将永远不会被回收。

解决办法:

  • 合理安排线程执行的时间,控制线程在Activity结束前结束。
  • 将内部类改为静态内部类,并使用弱引用WeakReference来保存Activity实例 因为弱引用只要GC发现了就会回收它 ,因此可尽快回收。
Handler的使用造成的内存泄漏

由于在Handler的使用中,handler会发送message对象到MessageQueue中 然后 Looper会轮询MessageQueue然后取出Message执行,但是如果一个Message长时间没被取出执行,那么由于 Message中有Handler的引用,而Handler 一般来说也是内部类对象,Message引用Handler

Handler引用Activity这样 使得Activity无法回收。或者说HandlerActivity退出时依然还有消息需要处理,那么这个Activity就不会被回收。

解决办法:使用静态内部类+弱引用的方式

资源未被及时关闭造成的内存泄漏

比如一些Cursor 没有及时close 会保存有Activity的引用,导致内存泄漏

解决办法:在onDestory方法中及时close即可

BitMap占用过多内存

Bitmap的解析需要占用内存,但是内存只提供8M的空间给BitMap,如果图片过多,并且没有及时recycle bitmap 那么就会造成内存溢出。

解决办法:及时recycle 压缩图片之后加载图片。

iOS 内存

iOS内存管理机制

iOS内存管理的基本思想就是引用计数,通过对象的引用计数来对内存对象的生命周期进行控制,主要有两种方式:

  • MRR(manual retain-release),人工引用计数,对象的生成、销毁、引用计数的变化都是由开发人员来完成。
  • ARC(Automatic Reference Counting),自动引用计数,只负责对象的生成,其他过程开发人员不再需要关心其销毁,使用方式类似于垃圾回收,但其实质还是引用计数。

引用计数

引用计数(Reference Count)是一个简单而有效的管理对象生命周期的方式。当我们创建一个新对象的时候,它的引用计数为 1,当有一个新的指针指向这个对象时,我们将其引用计数加1

当某个指针不再指向这个对象时,我们将其引用计数减 1,当对象的引用计数变为 0 时,说明这个对象不再被任何指针指向了,这个时候我们就可以将对象销毁,回收内存。

ARC 下的内存管理问题

ARC 能够解决 iOS 开发中 90% 的内存管理问题,但是另外还有 10% 内存管理,是需要开发者自己处理的,这主要就是与底层Core Foundation 对象交互的那部分,底层的 Core Foundation 对象由于不在ARC 的管理下,所以需要自己维护这些对象的引用计数。

对于 ARC盲目依赖的 iOS研发人员,可能会出现如下问题:

  • 过度使用 block之后,无法解决循环引用问题。
  • 遇到底层Core Foundation 对象,需要自己手工管理它们的引用计数时容易产生内存泄漏。
循环引用(Reference Cycle)问题

如下图所示:对象 A 和对象 B,相互引用了对方作为自己的成员变量,只有当自己销毁时,才会将成员变量的引用计数减 1。因为对象 A 的销毁依赖于对象 B 销毁,而对象 B 的销毁与依赖于对象 A 的销毁,这样就造成了我们称之为循环引用(Reference Cycle)的问题,这两个对象即使在外界已经没有任何指针能够访问到它们了,它们也无法被释放。

不止两对象存在循环引用问题,多个对象依次持有对方,形式一个环状,也可以造成循环引用问题,而且在真实编程环境中,环越大就越难被发现,从而造成内存泄漏。

主动断开循环引用

解决循环引用问题可以在合理的位置主动断开环中的一个引用,使得对象得以回收。如下图所示:

内存测试

Instruments内存分析

打开Instruments 然后选择 Leaks进入主界面,选择测试设备和测试应用点击开始执行,底部菜单选择CallTree(如下图),并在底部勾选hide System Libraries隐藏系统库函数。

内存测试

首先点击顶部的leaks Checkes 然后点击底部Cycles & Roots,就可以看到以图形方式显示出来的循环引用。这样我们就可以非常方便地找到循环引用的对象了。

延伸思考

为何iPhone设备内存小但是运行比内存更大的Android 设备更流畅?

在iOS中,应用切换到后台时其实是保留一张截屏然后关闭应用,后台的消息通知功能则通过苹果自身的服务来完成。因为后台应用是关闭状态,所以如果内存不够时可以将整个应用的状态从内存转移到手机存储中,下次打开应用时再从存储空间调回到内存。

除了某些应用必须使用后台的功能以外(例如音乐类应用在后台播放)他们都会在存储空间里乖乖坐好,内存可以完全为前台应用服务而不会被后台占用。得益于苹果采用的NVMe闪存超快的顺序读写速度,内存和存储空间中的数据可以迅速地相互传输。

然而Android的后台应用们很多都是持续运行在内存中,为了保护自己不被系统关闭,他们还需要一直在你的后台搞事情,包括且不限于互相伤害。虽然技术上Android也可以实现类似iOS那样的后台机制,但现实情况很骨感。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-12-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 QA一隅 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Android 内存管理
    • 内存管理机制
      • 分配机制
        • 回收机制
          • 内存分类
            • VSS
            • RSS
            • PSS
            • USS
          • Android 内存测试
            • 获取设备内存信息
            • 获取应用内存占用信息
            • 获取指定包的内存占用情况
            • 重点关注参数
            • 其他参数
          • 自动化获取性能数据
            • 内存泄漏
              • Android内存泄漏原因
          • iOS 内存
            • iOS内存管理机制
              • 引用计数
                • ARC 下的内存管理问题
                  • 循环引用(Reference Cycle)问题
                  • 主动断开循环引用
                • 内存测试
                  • Instruments内存分析
                  • 内存测试
              • 延伸思考
              相关产品与服务
              数据保险箱
              数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档