2018-09-17 14:26:00 u012109585 阅读数 176

获取 iOS APP 内存占用的大小

当我们想去获取 iOS 应用的占用内存时,通常我们能找到的方法是这样的,用 resident_size

 
#import <mach/mach.h>
- (int64_t)memoryUsage {
    int64_t memoryUsageInByte = 0;
    struct task_basic_info taskBasicInfo;
    mach_msg_type_number_t size = sizeof(taskBasicInfo);
    kern_return_t kernelReturn = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t) &taskBasicInfo, &size);
    
    if(kernelReturn == KERN_SUCCESS) {
        memoryUsageInByte = (int64_t) taskBasicInfo.resident_size;
        NSLog(@"Memory in use (in bytes): %lld", memoryUsageInByte);
    } else {
        NSLog(@"Error with task_info(): %s", mach_error_string(kernelReturn));
    }
    
    return memoryUsageInByte;
}

 

但是测试的时候,我们会发现这个跟我们在 Instruments 里面看到的内存大小不一样,有时候甚至差别很大。更加准确的方式应该是用 phys_footprint

 
#import <mach/mach.h>
- (int64_t)memoryUsage {
    int64_t memoryUsageInByte = 0;
    task_vm_info_data_t vmInfo;
    mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
    kern_return_t kernelReturn = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
    if(kernelReturn == KERN_SUCCESS) {
        memoryUsageInByte = (int64_t) vmInfo.phys_footprint;
        NSLog(@"Memory in use (in bytes): %lld", memoryUsageInByte);
    } else {
        NSLog(@"Error with task_info(): %s", mach_error_string(kernelReturn));
    }
    return memoryUsageInByte;

 

关于 phys_footprint 的定义可以在 XNU 源码中,找到 osfmk/kern/task.c 里对于 phys_footprint 的注释:

 
/*
 * phys_footprint
 *   Physical footprint: This is the sum of:
 *     + (internal - alternate_accounting)
 *     + (internal_compressed - alternate_accounting_compressed)
 *     + iokit_mapped
 *     + purgeable_nonvolatile
 *     + purgeable_nonvolatile_compressed
 *     + page_table
 *
 * internal
 *   The task's anonymous memory, which on iOS is always resident.
 *
 * internal_compressed
 *   Amount of this task's internal memory which is held by the compressor.
 *   Such memory is no longer actually resident for the task [i.e., resident in its pmap],
 *   and could be either decompressed back into memory, or paged out to storage, depending
 *   on our implementation.
 *
 * iokit_mapped
 *   IOKit mappings: The total size of all IOKit mappings in this task, regardless of
     clean/dirty or internal/external state].
 *
 * alternate_accounting
 *   The number of internal dirty pages which are part of IOKit mappings. By definition, these pages
 *   are counted in both internal *and* iokit_mapped, so we must subtract them from the total to avoid
 *   double counting.
 */

 

注释里提到的公式计算的应该才是应用实际使用的物理内存。

转载自新浪博客

posted on 2018-09-17 14:26 CodeVector 阅读(...) 评论(...) 编辑 收藏

2016-12-27 11:39:16 kaoshibiguo_1 阅读数 2610

 最近尝试对app内存使用情况进行检测对比,由于是刚刚接触这方面的知识,在很多方面都是处于一个认知的阶段,下面通过以下例子来进行分析对比:

一、(1)一个页面正常的情况下内存的使用情况:

从上图可以看出,这个页面的内存使用是比较平缓的,只是在加载数据或者进行点击事件的时候就会产生一些波动,当点击事件结束或者退出这个页面的时候就会出现一些灰色的区域,代表着这部分的内存已经被回收掉了。接下来通过memory analyzer生成内存使用饼状图,

从上面的图我们只是能看到内存在各个方面使用的大概比例,为了能够直观的体现出来区别,我让其与一个存在内存溢出的例子进行对比。

(2) 内存溢出的情况:

在原来的代码加上以下代码:


在这之后,重复进行“进入—退出”这个界面的操作,我们会发现内存使用会发生很大的变化。



内存使用成倍增长,而且出现了很多凹凸不平的峰值,通过MAT查询语句查询的结果如下:



当我退出这个界面,内存还存在着很多个社区话题详情(CommunityDetailActivity)页面,这明显出现了不正常,退出了这个Activity会回收掉这个页面所消耗的内存,这里非但没有回收掉,反而一直上升,通过上面的方法我们可以定位到CommunityTopicListAdapter中的Thread中,经过查找可以发现CommunityDetailActivity被内部类引用,而内部类又被线程引用,因此退出该页面的时候无法释放,GC无法回收造成内存泄漏。

解决方法:在使用线程的时候控制好睡眠的时间。

二、在很多时候我们通常会用到ListView进行开发,我们会发现在使用适配器的时候通常会进行控件复用来减少对内存的消耗,事实上不知道用跟没有用的区别区别在哪里,所以我通过下面的例子进行对比分析:


使用控件复用的情况(图一)



没有使用控件复用的情况(图二)

使用控件复用时内存消耗较大的几项



没有使用控件复用时内存消耗较大的几项

从图中我们可以看到ListView持有了大量的对象引用,其中TextView数量达到1000多,而在正常情况下,ListView会复用类型相同的view,其中的对象个数不可能如此庞大,因此,从这里就可以断定ListView使用不当出现了内存泄漏。


三、WebView加载html



从上图可以看到,Webview如果加载的页面有很多图片就会发现内存占用会上升,当退出这个页面的重新进来,JVM就会把一些内存释放掉,让webview在加载html时处于一个“上升—下降”的状态,不过通过图片可以看到,在不断加载和浏览多个html后内存会有所上升,因为它在不断加载的过程中会产生一些缓存数据。

解决方法:在退出该webview页面的时候把webview的缓存历史清除掉,webview.clearHistory();

webview.clearCache(true);

webview.freeMemory();

webview = null;


四、我们在使用MAT分析这些页面的时候会发现,大多数情况下MAT会把"android.graphics.Bitmap"作为内存泄漏的怀疑对象,结果如图所示:


dominator_tree页面我们可以看出来因为"android.graphics.Bitmap"Retained Head是比较大的,在分析内存泄漏时,内存最大的是需要去怀疑是否存在着泄漏。


所以下面就对"android.graphics.Bitmap"进行分析,经过Path To GC Roots-> exclude weak references过滤掉弱引用可以得到下图:


从上图可以看出来最后的子文件的文件图标下面有一个黄色的小点,这代表着能够被GC Roots访问到,这就代表着不能被回收掉,这就解决了为什么Mat一直把"android.graphics.Bitmap"作为怀疑的对象。

2019-06-26 16:49:57 u013602835 阅读数 594

     最近在调研iOS中的OOM(Out-Of-Memory),iOS中存在一些机制,当系统的内存不够用时或者当前APP的使用内存超过了阈值,就会导致系统强杀当前APP,由于强杀当前APP的进程是系统做的事情,所以,当前APP是无法知道是什么时候被强杀的。而且,我们平常使用的通过监测signal信号量来获取Crash的工具也是无法获取OOM这类强杀的。在调研测试过程中,用到了计算当前APP占用内存的计算方法和CPU使用率的计算方法,在此记录一下。

 

获取当前APP占用系统内存的方法如下:

#import <mach/mach.h>

- (int64_t)memoryUsage {
    int64_t memoryUsageInByte = 0;
    task_vm_info_data_t vmInfo;
    mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
    kern_return_t kernelReturn = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
    if(kernelReturn == KERN_SUCCESS) {
        memoryUsageInByte = (int64_t) vmInfo.phys_footprint;
        NSLog(@"APP占用内存: %lld字节(B)", memoryUsageInByte);
        int64_t mb = memoryUsageInByte / 1024 / 1024;
        NSLog(@"APP占用内存: %lld兆(MB)", mb);
    } else {
        NSLog(@"Error with task_info(): %s", mach_error_string(kernelReturn));
    }
    return memoryUsageInByte;
}

 

计算当前APP的CPU使用率的方法(数值与Instrument计算值接近):

- (float)cpu_usage
{
    kern_return_t kr;
    task_info_data_t tinfo;
    mach_msg_type_number_t task_info_count;
    
    task_info_count = TASK_INFO_MAX;
    kr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)tinfo, &task_info_count);
    if (kr != KERN_SUCCESS) {
        return -1;
    }
    
    task_basic_info_t      basic_info;
    thread_array_t         thread_list;
    mach_msg_type_number_t thread_count;
    
    thread_info_data_t     thinfo;
    mach_msg_type_number_t thread_info_count;
    
    thread_basic_info_t basic_info_th;
    uint32_t stat_thread = 0; // Mach threads
    
    basic_info = (task_basic_info_t)tinfo;
    
    // get threads in the task
    kr = task_threads(mach_task_self(), &thread_list, &thread_count);
    if (kr != KERN_SUCCESS) {
        return -1;
    }
    if (thread_count > 0)
        stat_thread += thread_count;
    
    long tot_sec = 0;
    long tot_usec = 0;
    float tot_cpu = 0;
    int j;
    
    for (j = 0; j < thread_count; j++)
    {
        thread_info_count = THREAD_INFO_MAX;
        kr = thread_info(thread_list[j], THREAD_BASIC_INFO,
                         (thread_info_t)thinfo, &thread_info_count);
        if (kr != KERN_SUCCESS) {
            return -1;
        }
        
        basic_info_th = (thread_basic_info_t)thinfo;
        
        if (!(basic_info_th->flags & TH_FLAGS_IDLE)) {
            tot_sec = tot_sec + basic_info_th->user_time.seconds + basic_info_th->system_time.seconds;
            tot_usec = tot_usec + basic_info_th->user_time.microseconds + basic_info_th->system_time.microseconds;
            tot_cpu = tot_cpu + basic_info_th->cpu_usage / (float)TH_USAGE_SCALE * 100.0;
        }
        
    } // for each thread
    
    kr = vm_deallocate(mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t));
    assert(kr == KERN_SUCCESS);
    
    return tot_cpu;
}

 

 

2017-02-16 11:16:03 L_weiguo 阅读数 4991
#include <sys/param.h>
#include <sys/mount.h>

- (void)getDivceSize{
    //可用大小
    struct statfs buf;
    long long freespace = -1;
    if(statfs("/var", &buf) >= 0){
        freespace = (long long)(buf.f_bsize * buf.f_bfree);
    }
    //总大小
    struct statfs buf1;
    long long maxspace = 0;
    if (statfs("/", &buf1) >= 0) {
        maxspace = (long long)buf1.f_bsize * buf1.f_blocks;
    }
    if (statfs("/private/var", &buf1) >= 0) {
        maxspace += (long long)buf1.f_bsize * buf1.f_blocks;
    }
    NSString * sizeStr = [NSString stringWithFormat:@"可用空间%0.2fG / 总空间%0.2fG",(double)freespace/1024/1024/1024,(double)maxspace/1024/1024/1024];
    self.sizeLabel.text = sizeStr;
    
}

2016-10-24 14:33:56 chillon_liao 阅读数 2214
 iPad1: 127MB/256MB/49% (crash amount/total amount/percentage of total)
    iPad2: 275MB/512MB/53%
    iPad3: 645MB/1024MB/62%
    iPad4: 585MB/1024MB/57% (iOS 8.1)
    iPad Mini 1st Generation: 297MB/512MB/58%
    iPad Mini retina: 696MB/1024MB/68% (iOS 7.1)
    iPad Air: 697MB/1024MB/68%
    iPad Air 2: 1195MB/2048MB/58%
    iPod touch 4th gen: 130MB/256MB/51% (iOS 6.1.1)
    iPod touch 5th gen: 286MB/512MB/56% (iOS 7.0)
    iPhone4: 325MB/512MB/63%
    iPhone5: 645MB/1024MB/62%
    iPhone5S: 646MB/1024MB/63%
    iPhone6: 645MB/1024MB/62%
    iPhone6+: 645MB/1024MB/62%
    iPhone6s: 1396MB/2048MB/68% (iOS 9.2)
    iPhone6s+: 1195MB/2048MB/58%
没有更多推荐了,返回首页