MTK内存管理机制简单分析

1:内存:

内存,在手机里面,是个较为紧缺的资源,特别是在功能机上面。经常在功能机上面产生的内存不足,申请失败的地方比比皆是,
更是屡见不鲜,经常会为了节省内存,会进行代码的优化,节省出一些空间出来。往往申请较大的比如700k之上的,总是需要考虑
谨慎,处理申请失败的情况。内存泄露,对于长期不关机的手机来说,更是一个潜在的威胁,对于设计人员的能力,则有较大的考
验。比如保证内存的申请与释放匹配,否则长期的累计,会使得内存可用一直在降低,最后导致没有可用内存可用,导致死机发生。
  内存碎片,也是一个需要注意的地方,比如设计不合理的内存管理机制,对于内存碎片未作较好的设计,会导致出现剩余空间很大,
但是连续的可用空间很小,导致无法申请较大的内存,使得功能受限,直接导致性能的衰弱。因此一般手机内存的管理,都会分块处理
,规划出一些空间,专门来为小内存的申请和释放,再规划一些空间,来进行大内存的分配管理,这样即可有效的规避掉内存碎片的
发生,MTk既是如此来处理的,当然其他的手机平台亦是如此考虑的。
2:开始来分析MTK内存的管理方案:
  首先,我们这边需要一个简化,便是将互斥操作直接忽略掉,直接关注核心处理。
  下面我们来说第一种分配的接口以及使用,一般是用在较大内存的申请,偏向驱动底层的内存分配,一般MMI不建议使用
  在med_mem.h存在如下的代码片段:
typedef union
{
    /* default size */
    kal_uint8 MED_DUFAULT_EXT_SIZE[MED_MEM_EXT_DEFAULT_SIZE];
    ......
    kal_uint8 MED_EXT_CAM_CAPTURE_W_FS_SORT_W_AUD[MED_MEM_CONC3_SIZE(MAX_MED_CAM_CAP_EXT_MEM_SIZE,MAX_FS_SORT_MEM_SIZE,AUD_EXT_MEM_SIZE)];
    ......

} med_ext_mem_union;
 #define MED_EXT_MEM_SIZE sizeof(med_ext_mem_union)

这个联合里面包含着各个需要从此内存池获取内存,各自需要的最大数值, sizeof(med_ext_mem_union) 得到的是联合里面最大的结构所占用的空间大小

随后在med_main.c里面有如下代码:
          #pragma arm section zidata = "LARGEPOOL_ZI"
        __align(4)     kal_uint8 med_ext_mem[MED_EXT_MEM_SIZE];
        #pragma arm section zidata
  这个数组便是在运行时作为内存分配空间使用的。这里来看下几个语法 
#pragma arm section zidata = "LARGEPOOL_ZI"
****
#pragma arm section zidata
这个代表的意思为中间的        __align(4)     kal_uint8 med_ext_mem[MED_EXT_MEM_SIZE];最终编译链接的位置,是属于段LARGEPOOL_ZI里面的,
从而链接到的位置会依赖以链接脚本的LARGEPOOL_ZI段的位置。zidata的意思为未初始化的变量,与zidata相关的便是ro,只读,rw可读可写,zi和
rw的区别便是zi不占用rom空间,因为不需要保存初始值,会在运行时初始化为0,而rw数据,是有初始数据的,因此会在rom和ram都会占用空间,来保存初始值
以及运行时的修改。
 __align(4)这个代表的是2的4次方对齐,来保证内存的起点在16的整数倍上,这样才能使得内存管理机制较好的处理和管理。
现在已经知道了内存分配的来源,下来来看看内存是如何管理以及分配的。
3:内存管理的初始化: 
  调用关系
  med_create--med_init--med_utility_init
  med_create里面存储的是一个结构,包含了5个信息,task的初始化函数,主要的消息循环函数,配置函数,重启函数,以及退出函数。
  med_init便是初始化函数。
  med_utility_init函数里面通过调用med_set_ext_memory_pool来将med_ext_mem数组和分配的管理结构关联起来,具体如下:
 
  void med_set_ext_memory_pool(address_t memory, size_type size)
  传递的参数为med_ext_mem,以及MED_EXT_MEM_SIZE,此时便会将这个数组的信息传递到管理结构里面,具体的为:

g_med_ext_mem_cntx.ext_mem_pool_id = kal_adm_create(
                                            memory,
                                            size,
                                            NULL,                                          
                                            KAL_FALSE
                                            );
    g_med_ext_mem_cntx.ext_mem_alloc_count = 0;
    g_med_ext_mem_cntx.ext_mem_left_size = size;
    
    g_med_ext_mem_cntx.temp_mem_list = NULL;
    g_med_ext_mem_cntx.is_debug_info_on = KAL_FALSE;
  
   kal_adm_create函数将med_ext_mem数组进行构造,返回出一个id,随后的申请都会围绕着这个id来进行。
   ext_mem_alloc_count ,申请计数
   ext_mem_left_size 大小(已使用的大小为: MED_EXT_MEM_SIZE-ext_mem_left_size)
4:内存的申请以及释放:
   med_alloc_ext_mem_ext这个函数是来处理申请的一个核心接口,其他上层的使用宏来进行调用,本质还是调用在此函数上面。
   此函数的接口参数为:
   申请大小,类别,文件,行号
   其中类别为:
   typedef enum
{
    MED_INT_MEMORY_TYPE,
    MED_EXT_MEMORY_TYPE_NONCACHEABLE,
    MED_EXT_MEMORY_TYPE_CACHEABLE,
    MED_EXT_MEMORY_TYPE_FRAMEBUFFER,
    MED_EXT_MEMORY_TYPE_TOPPEST_NONCACHEABLE,
    MED_EXT_MEMORY_TYPE_TOPPEST_CACHEABLE,
    MED_EXT_MEMORY_TYPE_AUDIO_NONCACHEABLE,
    MED_EXT_MEMORY_TYPE_AUDIO_CACHEABLE,
    MED_EXT_MEMORY_TYPE_COUNT
} med_memory_type_enum;
  med_alloc_ext_mem_ext函数的关键处理过程:

kal_take_mutex(med_mem_mutex); //获取互斥操作信号量
    p = (void*)med_ext_smalloc_ext((size_type) size, location, file_p, line_p);
    kal_give_mutex(med_mem_mutex);//释放互斥操作信号量
   具体来看看med_ext_smalloc_ext这个函数吧:
    这个函数会来依据med_memory_type_enum来进行处理,具体的由于没有源码,不好说明,但是基本可以描述下:  
    有一个标示着为MED_MEMORY_WITH_TEMPORARY_FLAG,有这个标示的话,申请时先查询是否已经释放,没有的话先释放再申请。
    一般是从低地址进行申请,如果类型为MED_EXT_MEMORY_TYPE_TOPPEST_CACHEABLE或者MED_EXT_MEMORY_TYPE_TOPPEST_NONCACHEABLE
     则会从高地址来进行获取。
    cacheable 和noncacheable的区别应该为申请的地方不同,具体的不可得知。
    通过这个方式来管理的还有与声音audio有关的申请,声音单独使用kal_adm_create重新构造一个内存区域来进行管理,应该是为了规避其他task的申请
    影响到声音相关关键申请,而导致品质下降或者严重的死机产生。
    以上便是MTK内存管理的一个方式,下来我们来说一般的小的内存申请的方式,一般限制在2k大小的很小的一个结构申请,一般的管理方案是由一组数组
    组成,比如:
    g_buffer[]=
    {
//多少字节 总共数目 数组地址
    {50,1000,g_50_buffer},
    {100,1000,g_100_buffer},
    }
    这里只是一个例子,不代表MTK就是如此数据,随后申请时比如申请20字节,那么调用接口OslMalloc(对应的释放为OslMfree)进行申请空间。
    函数会在g_buffer里面查找,看当前50字节是否有剩余,有则返回g_50_buffer里面空闲的一项地址,然后进行修正剩余空闲数目,以备其他申请或者查询使用。
    如果50字节的1000个都被申请完了,那么便会进入100字节里面查询,如果有空闲,返回地址,没有继续查询,直到数组结束,数组结束也没有分配成功,则
    会产生断言,死机重启。
3:app的申请内存管理方案分析:
   ASM =application shared Memory ,这种机制是为了AP直接共享内存而产生的,比之Med第一种的分配管理,这个便多了更多的一些细节,可以更加友好的实现
   在内存不足时,提示用户是否愿意释放一些空间,来满足当前ap的运行使用。
   首先,我们先来看看内存分配数组的结构:
   app_mem_config.h里面:
    typedef union
{
    kal_uint8 SUB_POOL[sizeof(app_asm_pool_sub_union) + GDI_ASM_MEM_SIZE];
    kal_uint8 DUFAULT_POOL[APPLIB_MEM_AP_POOL_SIZE_CONFIG(APPLIB_MEM_AP_POOL_DEFAULT_SIZE)];
    .....
    kal_uint8 APP_UNIT_TEST[APPLIB_MEM_AP_POOL_SIZE_CONFIG(APPMEM_TEST_POOL_SIZE)];
    ......

} app_asm_pool_union;  
 #define APPLIB_MEM_AP_POOL_SIZE sizeof(app_asm_pool_union)
       是不是和Med第一种的分配管理基本保持一致呢?其实此时就是保持一致的。下来看下内存分配的数组的位置:
       MemoryRes.c里面:
       ALIGN(ASM_ALIGN_SIZE)  U8 g_applib_mem_ap_pool[APPLIB_MEM_AP_POOL_SIZE + 10240];
       这个就不需要解释了吧。
    我们再看看初始化这个数组的地方吧:
    MMI_Init--mmi_frm_appmem_stage1_init--applib_mem_ap_init
    MMI_Init在TaskInit.c里面的mmi_handler_info数组里面。
    我们现在来细看下applib_mem_ap_init函数:
     参数为 stop_finish_callback_by_MMI,g_applib_mem_ap_pool,APPLIB_MEM_AP_POOL_SIZE 这里需要说明stop_finished_handler函数的意义
    这里这个函数的目的是当一个应用申请失败时,会弹出是否需要释放其他应用来满足此应用的运行,(这里是否弹出需要释放其他应用内存,也是由用户来配置的,不需要的话
    便跟一般的申请内存一致了),当点击释放时,会调用注册的释放函数来完成释放,释放完毕后,会通知应用释放完毕,来进行再次尝试启动。
    applib_mem_ap_init这个函数内部的实现为:
        g_applib_mem_cntx.app_pool_id = kal_adm_create(
                                        g_applib_mem_ap_pool,
                                        APPLIB_MEM_AP_POOL_SIZE,
                                        (kal_uint32*) g_applib_mem_pool_chunk_size,
                                        KAL_FALSE);
    
    ASM_ASSERT(stop_finish_callback_by_MMI != NULL);
    g_applib_mem_cntx.app_stop_finish_callback = stop_finish_callback_by_MMI;
    g_applib_mem_cntx.app_pool_inited = KAL_TRUE;
    g_applib_mem_cntx.app_pool      = g_applib_mem_ap_pool;
    g_applib_mem_cntx.app_pool_size = APPLIB_MEM_AP_POOL_SIZE;
    //这块便是和Med第一种的分配管理基本一致了
    initialize_UI_demo--mmi_frm_appmem_init这个结构里面,便是赋值默认的管理申请内存失败,停止回调以及默认释放函数,以及预检测内存函数,预检测
    内存函数可以先进行检测是否能够申请得到内存。
4:ASM的管理数据结构:
   static applib_mem_cntx_struct g_applib_mem_cntx;
   这个结构保存着所有的相关信息,具体结构的信息为:

typedef struct
{
    /**************************************************************************
     * app *
    **************************************************************************/

/* ADM pool ID of app-based ASM. */
    KAL_ADM_ID app_pool_id;  //创建时保存的id,随后申请内存时需要

/* memory buffer pool */
    void *app_pool;  // 创建的内存分配地址

/* buffer pool size */
    kal_uint32 app_pool_size; // 创建的内存分配大小

/* Count of allocated app-based blocks */
    kal_int32 app_alloc_count; //申请的计数

/* Callback handler to process the result of stopping application in MMI task */
    app_stop_finish_callback_type app_stop_finish_callback; //停止应用的回调函数

/* allocation fail handler */
    applib_mem_ap_allocation_fail_handler_type app_allocation_fail_handler;//申请失败的函数

/* default stop callback */
    applib_mem_stop_handler_type app_stop_callback_default;//默认的停止函数

/* callback before allocate memory */
    applib_mem_ap_pre_alloc_hdlr app_pre_alloc_handler; //预申请的函数

/* callback after memory is freed */
    applib_mem_freed_handler mem_freed_handler;//释放后的函数

/* Head node of app-based chunk */
    applib_mem_header_struct app_head;//记录着使用情况

/* Initialized */
    kal_bool app_pool_inited; //是否已初始化

/* app stop info */
    applib_mem_app_stop_info_struct app_stop_info[APPLIB_MEM_APP_STOP_MAX];//记录enum的stop的信息

/* application info */    
    applib_mem_app_info_struct app_info[APPLIB_MEM_APP_COUNT];// 记录asm申请时的ap id信息

/* Multi-thread mutex */
    mmi_frm_recursive_mutex_struct app_asm_mutex;//互斥信号
    ....去除掉了screen的一组数据,管理是和app这个是一致的。

} applib_mem_cntx_struct;
 现在我们来看看一个关键的定义APPLIB_MEM_APP_COUNT,这个数值。
  在app_mem.h里面有这个一个枚举:applib_mem_ap_id_enum
   内容为:
   typedef enum {

APPLIB_MEM_AP_ID_DUMMY,
    APPLIB_MEM_AP_ID_QQ,
    APPLIB_MEM_AP_ID_IVEX,
    APPLIB_MEM_AP_ID_EM,
    .....
    APPLIB_MEM_AP_ID_VENUS,
    ......
    APPLIB_MEM_AP_ID_QQ_MOVIE,
    APPLIB_MEM_AP_ID_MARK_SEVERAL,
    APPLIB_MEM_AP_ID_TOTAL
} applib_mem_ap_id_enum;
  APPLIB_MEM_APP_COUNT =APPLIB_MEM_AP_ID_TOTAL-APPLIB_MEM_AP_ID_DUMMY
  这个枚举便是随后你申请空间时的一个关键依赖值,下面来看看这个空间的申请方式:
  关键函数1:applib_mem_ap_register
  参数applib_mem_ap_id_enum值,弹出框时的字串信息,弹出框时的图标,停止函数(当用户点击停止时会调用,释放内存,通知asm管理来处理数据)
  关键函数2:applib_mem_ap_alloc申请空间函数:
  参数applib_mem_ap_id_enum值,申请大小
  下来便是asm和其他的区别了:
   如果申请失败,可以调用 mmi_frm_appmem_prompt_to_release_mem函数来进行释放当前申请空间的一些应用,这个函数的参数为:
   pplib_mem_ap_id_enum值,图标,所需要的内存大小,释放成功后的函数(来完成释放后重新启动的动作)
   函数接口:
    applib_mem_ap_get_total_left_size 获取总共剩余的空间
    applib_mem_ap_get_max_alloc_size 获取最大可以申请的空间
    applib_mem_ap_get_pool_size 获取总数
    applib_mem_ap_alloc_full_pool_int 这个为申请pool上的所有空间,这个接口会占完全部的空间,如果不释放时,
    再去申请的话,会失败。
5:ASM里面的screen的内存管理:
    屏幕 screen的内存管理,结构上和APP Asm的管理完全一致,仅是接口的不同而已。

总结:
     内存管理算是操作系统中设计关键部分之一,在手机的平台上,内存管理的算法设计考虑,若不能有效的来规避内存碎片,则会导致性能指数下降,
     直接影响到系统的存活周期,因此往往都会在内存的管理方案上下足成本,当然当前成熟的设计思路也是有效避免内存碎片,分割的无法使用的有效策略。
     看过几个其他的平台(mstar和展讯),内存申请无外乎这些考虑,但是相比而言,mstar的封装很好,不需要关注到底申请到哪里的空间内存,上层接口
     保持一致,如此便保证了用户层的统一,不至有所迷惑,一致不知所措。

MTK:内存管理机制简单分析相关推荐

  1. flink分析使用之八内存管理机制

    一.flink内存机制 在前面的槽机制上,提到了内存的共享,这篇文章就分析一下,在Flink中对内存的管理.在Flink中,内存被抽象出来,形成了一套自己的管理机制.Flink本身基本是以Java语言 ...

  2. caffe源码分析--SyncedMemory 内存管理机制

    caffe源码分析–SyncedMemory 内存管理机制 ​ SyncedMemory 是caffe中用来管理内存分配和CPU.GPU数据及同步的类,只服务于Blob类.SyncedMemory 对 ...

  3. python内存管理机制错误_Python内存管理机制和垃圾回收机制的简单理解

    一.内存管理机制 1.由c开发出来的cpython 2.include / objests 3.需要下载python源码包 4.Pyobject:float PyVarObject: 5.在pytho ...

  4. 二进制安全:ptmalloc内存管理机制与堆块chunk源码分析

    敬告: <中华人民共和国刑法>第三百八十六条[破坏计算机系统罪:网络服务渎职罪]违反国家规定,对计算机信息系统功能进行删除.修改.增加.干扰,造成计算机系统不能正常运行,后果严重的,处五年 ...

  5. 什么是 Python 的 「内存管理机制」?

    什么是内存管理器(what) Python作为一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言,与大多数编程语言不同,Python中的变量无需事先申明,变量无需指定类型,程序员无需关心内存 ...

  6. JVM内存管理机制线上问题排查

    本文主要基于"深入java虚拟机"这本书总结JVM的内存管理机制,并总结了常见的线上问题分析思路.文章最后面是我对线上故障思考的ppt总结. Java内存区域 虚拟机运行时数据区如 ...

  7. 浅析java内存管理机制

    内存管理是计算机编程中的一个重要问题,一般来说,内存管理主要包括内存分配和内存回收两个部分.不同的编程语言有不同的内存管理机制,本文在对比C++和java语言内存管理机制的不同的基础上,浅析java中 ...

  8. 【Python基础】什么是Python的 “内存管理机制”

    什么是内存管理器(what) Python作为一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言,与大多数编程语言不同,Python中的变量无需事先申明,变量无需指定类型,程序员无需关心内存 ...

  9. cocos2dx标准容器_cocos2dx[3.2](24)——内存管理机制

    [唠叨] 整合参考文档. [参考] [内存管理机制] 在3.x版本,Cocos2d-x采用全新的根类 Ref,实现Cocos2d-x 类对象的引用计数记录.引擎中的所有类都派生自Ref. 1.引用计数 ...

最新文章

  1. 扶稳!四大步“上手”超参数调优教程,就等你出马了 | 附完整代码
  2. 图像处理(一)图像变形(1)矩形全景图像还原-Siggraph 2014
  3. mysql命令行卡在>>>>>
  4. UV认证应用安全标准的目的
  5. 图片怎么等比缩放_mac图像缩放工具Teorex iResizer
  6. Taro+react开发(71):Taro.nextTick
  7. bottomTagFragment
  8. 软件测试的现实和理想
  9. 拆点并查集(poj 1182: 食物链)
  10. Python高性能编程指南大纲
  11. Linux基础软件威胁疑云:从已知到“未知”
  12. JDK Required: 'tools.jar' seems to be not in IDEA classpath解决办法
  13. Java多线程---Phaser
  14. 报错“The C compiler identification is unknown……”解决办法
  15. hp,Qlogic,Brocade光纖卡查看方式
  16. html2canvas的使用以及跨域问题
  17. 内存申请 GFP_KERNEL GFP_ATOMIC
  18. easyswoole连接mysql
  19. CSS进阶(5)- 浏览器兼容性
  20. 安得指针千万间,大庇天下地址具欢颜(中)

热门文章

  1. linux---多线程---信号量--不懂
  2. 学习笔记41—ttest误区
  3. SQL Server 数据库调整表中列的顺序操作
  4. Linux设备中的并发控制
  5. appium自动化测试(5)-一些pyhon操作
  6. 已知: 每个飞机只有一个油箱, 飞机之间可以相互加油(注意是相互,没有加油机) 一箱油可供一架飞机绕地球飞半圈,问题:为使至少一架飞机绕地球一圈回到起飞时的飞机...
  7. 求平均值 Avg.java
  8. 解决CentOS中无法使用setup命令 -bash:setup: command
  9. Linux 大文件快速处理小的办法
  10. ubuntu 一张网卡绑定多个ip