Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析(2)

简介:
    回到前面MemoryHeapBase类的构造函数中,将匿名共享内存映射到本进程的地址空间去后,还看继续设置这块匿名共享内存的读写属性:

  
  
  1. if (fd >= 0) {   
  2.     if (mapfd(fd, size) == NO_ERROR) {   
  3.         if (flags & READ_ONLY) {   
  4.             ashmem_set_prot_region(fd, PROT_READ);   
  5.         }   
  6.     }   
  7. }   
      上面调用mapfd函数来映射匿名共享内存时,指定这块内存是可读写的,但是如果传进来的参数flags设置了只读属性,那么还需要调用系统运行时库存层的ashmem_set_prot_region函数来设置这块匿名共享内存为只读,这个函数定义在system/core/libcutils/ashmem-dev.c文件,有兴趣的读者可以自己去研究一下。
 
        这样,通过这个构造函数,一块匿名共享内存就建立好了,其余的三个成员函数getHeapID、getBase和getSize就简单了:

  
  
  1. int MemoryHeapBase::getHeapID() const {   
  2.     return mFD;   
  3. }   
  4.    
  5. void* MemoryHeapBase::getBase() const {   
  6.     return mBase;   
  7. }   
  8.    
  9. size_t MemoryHeapBase::getSize() const {   
  10.     return mSize;   
  11. }   
  接下来我们再来看一下MemoryHeapBase在Client端实现的类图:
         这个类图中的类也是可以划分为两部分,一部分是和业务相关的,即跟匿名共享内存操作相关的类,包括BpMemoryHeap、IMemoryBase和RefBase三个类,另一部分是和Binder机制相关的,包括IInterface、BpInterface、BpRefBase、IBinder、BpBinder、ProcessState和IPCThreadState七个类。
        在和匿名共享内存操作相关的类中,BpMemoryHeap类是前面分析的MemoryHeapBase类在Client端进程的远接接口类,当Client端进程从Service Manager或者其它途径获得了一个MemoryHeapBase对象的引用之后,就会在本地创建一个BpMemoryHeap对象来代表这个引用。BpMemoryHeap类同样是要实现IMemoryHeap接口,同时,它是从RefBase类继承下来的,因此,它可以与智能指针来结合使用。
        在和Binder机制相关的类中,和Server端实现不一样的地方是,Client端不需要实现BnInterface和BBinder两个类,但是需要实现BpInterface、BpRefBase和BpBinder三个类。BpInterface类继承于BpRefBase类,而在BpRefBase类里面,有一个成员变量mRemote,它指向一个BpBinder对象,当BpMemoryHeap类需要向Server端对象发出请求时,它就会通过这个BpBinder对象的transact函数来发出这个请求。这里的BpBinder对象是如何知道要向哪个Server对象发出请深圳市的呢?它里面有一个成员变量mHandle,它表示的是一个Server端Binder对象的引用值,BpBinder对象就是要通过这个引用值来把请求发送到相应的Server端对象去的了,这个引用值与Server端Binder对象的对应关系是在Binder驱动程序内部维护的。这里的ProcessSate类和IPCThreadState类的作用和在Server端的作用是类似的,它们都是负责和底层的Binder驱动程序进行交互,例如,BpBinder对象的transact函数就通过线程中的IPCThreadState对象来将Client端请求发送出去的。这些实现具体可以参考 Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析 一文。
        这里我们主要关注BpMemoryHeap类是如何实现IMemoryHeap接口的,这个类声明和定义在frameworks/base/libs/binder/IMemory.cpp文件中:

  
  
  1. class BpMemoryHeap : public BpInterface<IMemoryHeap>   
  2. {   
  3. public:   
  4.     BpMemoryHeap(const sp<IBinder>& impl);   
  5.     ......   
  6.    
  7.     virtual int getHeapID() const;   
  8.     virtual void* getBase() const;   
  9.     virtual size_t getSize() const;   
  10.    
  11.     ......   
  12. private:   
  13.     mutable volatile int32_t mHeapId;   
  14.     mutable void*       mBase;   
  15.     mutable size_t      mSize;   
  16.    
  17.     ......   
  18. }   
 先来看构造函数BpMemoryHeap的实现:

  
  
  1. BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)   
  2.     : BpInterface<IMemoryHeap>(impl),   
  3.         mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)   
  4. {   
  5. }   
        它的实现很简单,只是初始化一下各个成员变量,例如,表示匿名共享内存文件描述符的mHeapId值初化为-1、表示匿名内共享内存基地址的mBase值初始化为MAP_FAILED以及表示匿名共享内存大小的mSize初始为为0,它们都表示在Client端进程中,这个匿名共享内存还未准备就绪,要等到第一次使用时才会去创建。这里还需要注意的一点,参数impl指向的是一个BpBinder对象,它里面包含了一个指向Server端Binder对象,即MemoryHeapBase对象的引用。
 
        其余三个成员函数getHeapID、getBase和getSize的实现是类似的:

  
  
  1. int BpMemoryHeap::getHeapID() const {   
  2.     assertMapped();   
  3.     return mHeapId;   
  4. }   
  5.    
  6. void* BpMemoryHeap::getBase() const {   
  7.     assertMapped();   
  8.     return mBase;   
  9. }   
  10.    
  11. size_t BpMemoryHeap::getSize() const {   
  12.     assertMapped();   
  13.     return mSize;   
  14. }   
   即它们在使用之前,都会首先调用assertMapped函数来保证在Client端的匿名共享内存是已经准备就绪了的:

  
  
  1. void BpMemoryHeap::assertMapped() const   
  2. {   
  3.     if (mHeapId == -1) {   
  4.         sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());   
  5.         sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));   
  6.         heap->assertReallyMapped();   
  7.         if (heap->mBase != MAP_FAILED) {   
  8.             Mutex::Autolock _l(mLock);   
  9.             if (mHeapId == -1) {   
  10.                 mBase   = heap->mBase;   
  11.                 mSize   = heap->mSize;   
  12.                 android_atomic_write( dup( heap->mHeapId ), &mHeapId );   
  13.             }   
  14.         } else {   
  15.             // something went wrong   
  16.             free_heap(binder);   
  17.         }   
  18.     }   
  19. }   
      在解释这个函数之前,我们需要先了解一下BpMemoryHeap是如何知道自己内部维护的这块匿名共享内存有没有准备就绪的。
       在frameworks/base/libs/binder/IMemory.cpp文件中,定义了一个全局变量gHeapCache:

  
  
  1. static sp<HeapCache> gHeapCache = new HeapCache();   
     它的类型为HeapCache,这也是一个定义在frameworks/base/libs/binder/IMemory.cpp文件的类,它里面维护了本进程中所有的MemoryHeapBase对象的引用。由于在Client端进程中,可能会有多个引用,即多个BpMemoryHeap对象,对应同一个MemoryHeapBase对象(这是由于可以用同一个BpBinder对象来创建多个BpMemoryHeap对象),因此,当第一个BpMemoryHeap对象在本进程中映射好这块匿名共享内存之后,后面的BpMemoryHeap对象就可以直接使用了,不需要再映射一次,当然重新再映射一次没有害处,但是会是多此一举,Google在设计这个类时,可以说是考虑得非常周到的。      
我们来看一下HeapCache的实现:

  
  
  1. class HeapCache : public IBinder::DeathRecipient   
  2. {   
  3. public:   
  4.     HeapCache();   
  5.     virtual ~HeapCache();   
  6.    
  7.     ......   
  8.    
  9.     sp<IMemoryHeap> find_heap(const sp<IBinder>& binder);   
  10.     void free_heap(const sp<IBinder>& binder);   
  11.     sp<IMemoryHeap> get_heap(const sp<IBinder>& binder);   
  12.     ......   
  13.    
  14. private:   
  15.     // For IMemory.cpp   
  16.     struct heap_info_t {   
  17.         sp<IMemoryHeap> heap;   
  18.         int32_t         count;   
  19.     };   
  20.    
  21.     ......   
  22.    
  23.     Mutex mHeapCacheLock;   
  24.     KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;   
  25. };   
  它里面定义了一个成员变量mHeapCache,用来维护本进程中的所有BpMemoryHeap对象,同时还提供了find_heap和get_heap函数来查找内部所维护的BpMemoryHeap对象的功能。函数find_heap和get_heap的区别是,在find_heap函数中,如果在mHeapCache找不到相应的BpMemoryHeap对象,就会把这个BpMemoryHeap对象加入到mHeapCache中去,而在get_heap函数中,则不会自动把这个BpMemoryHeap对象加入到mHeapCache中去。
 
       这里,我们主要看一下find_heap函数的实现:

  
  
  1. sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)   
  2. {   
  3.     Mutex::Autolock _l(mHeapCacheLock);   
  4.     ssize_t i = mHeapCache.indexOfKey(binder);   
  5.     if (i>=0) {   
  6.         heap_info_t& info = mHeapCache.editValueAt(i);   
  7.         LOGD_IF(VERBOSE,   
  8.                 "found binder=%p, heap=%p, size=%d, fd=%d, count=%d",   
  9.                 binder.get(), info.heap.get(),   
  10.                 static_cast<BpMemoryHeap*>(info.heap.get())->mSize,   
  11.                 static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,   
  12.                 info.count);   
  13.         android_atomic_inc(&info.count);   
  14.         return info.heap;   
  15.     } else {   
  16.         heap_info_t info;   
  17.         info.heap = interface_cast<IMemoryHeap>(binder);   
  18.         info.count = 1;   
  19.         //LOGD("adding binder=%p, heap=%p, count=%d",   
  20.         //      binder.get(), info.heap.get(), info.count);   
  21.         mHeapCache.add(binder, info);   
  22.         return info.heap;   
  23.     }   
  24. }   
    这个函数很简单,首先它以传进来的参数binder为关键字,在mHeapCache中查找,看看是否有对应的heap_info对象info存在,如果有的话,就增加它的引用计数info.count值,表示这个BpBinder对象多了一个使用者;如果没有的话,那么就需要创建一个heap_info对象info,并且将它加放到mHeapCache中去了。1




本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966900,如需转载请自行联系原作者
目录
相关文章
|
8月前
|
存储 弹性计算 缓存
阿里云服务器ECS经济型、通用算力、计算型、通用和内存型选购指南及使用场景分析
本文详细解析阿里云ECS服务器的经济型、通用算力型、计算型、通用型和内存型实例的区别及适用场景,涵盖性能特点、配置比例与实际应用,助你根据业务需求精准选型,提升资源利用率并降低成本。
543 3
|
4月前
|
设计模式 缓存 Java
【JUC】(4)从JMM内存模型的角度来分析CAS并发性问题
本篇文章将从JMM内存模型的角度来分析CAS并发性问题; 内容包含:介绍JMM、CAS、balking犹豫模式、二次检查锁、指令重排问题
152 1
|
7月前
|
存储 人工智能 自然语言处理
AI代理内存消耗过大?9种优化策略对比分析
在AI代理系统中,多代理协作虽能提升整体准确性,但真正决定性能的关键因素之一是**内存管理**。随着对话深度和长度的增加,内存消耗呈指数级增长,主要源于历史上下文、工具调用记录、数据库查询结果等组件的持续积累。本文深入探讨了从基础到高级的九种内存优化技术,涵盖顺序存储、滑动窗口、摘要型内存、基于检索的系统、内存增强变换器、分层优化、图形化记忆网络、压缩整合策略以及类操作系统内存管理。通过统一框架下的代码实现与性能评估,分析了每种技术的适用场景与局限性,为构建高效、可扩展的AI代理系统提供了系统性的优化路径和技术参考。
451 4
AI代理内存消耗过大?9种优化策略对比分析
|
7月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
251 26
|
9月前
|
缓存 编解码 Android开发
Android内存优化之图片优化
本文主要探讨Android开发中的图片优化问题,包括图片优化的重要性、OOM错误的成因及解决方法、Android支持的图片格式及其特点。同时介绍了图片储存优化的三种方式:尺寸优化、质量压缩和内存重用,并详细讲解了相关的实现方法与属性。此外,还分析了图片加载优化策略,如异步加载、缓存机制、懒加载等,并结合多级缓存流程提升性能。最后对比了几大主流图片加载框架(Universal ImageLoader、Picasso、Glide、Fresco)的特点与适用场景,重点推荐Fresco在处理大图、动图时的优异表现。这些内容为开发者提供了全面的图片优化解决方案。
374 1
|
11月前
|
存储 Java
课时4:对象内存分析
接下来对对象实例化操作展开初步分析。在整个课程学习中,对象使用环节往往是最棘手的问题所在。
107 4
|
11月前
|
Java 编译器 Go
go的内存逃逸分析
内存逃逸分析是Go编译器在编译期间根据变量的类型和作用域,确定变量分配在堆上还是栈上的过程。如果变量需要分配在堆上,则称作内存逃逸。Go语言有自动内存管理(GC),开发者无需手动释放内存,但编译器需准确分配内存以优化性能。常见的内存逃逸场景包括返回局部变量的指针、使用`interface{}`动态类型、栈空间不足和闭包等。内存逃逸会影响性能,因为操作堆比栈慢,且增加GC压力。合理使用内存逃逸分析工具(如`-gcflags=-m`)有助于编写高效代码。
239 2
|
存储 算法 安全
基于哈希表的文件共享平台 C++ 算法实现与分析
在数字化时代,文件共享平台不可或缺。本文探讨哈希表在文件共享中的应用,包括原理、优势及C++实现。哈希表通过键值对快速访问文件元数据(如文件名、大小、位置等),查找时间复杂度为O(1),显著提升查找速度和用户体验。代码示例展示了文件上传和搜索功能,实际应用中需解决哈希冲突、动态扩容和线程安全等问题,以优化性能。
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
523 1

热门文章

最新文章