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,如需转载请自行联系原作者
目录
相关文章
|
28天前
|
缓存 Java Linux
如何解决 Linux 系统中内存使用量耗尽的问题?
如何解决 Linux 系统中内存使用量耗尽的问题?
115 48
|
10天前
|
机器学习/深度学习 人工智能 缓存
【AI系统】推理内存布局
本文介绍了CPU和GPU的基础内存知识,NCHWX内存排布格式,以及MNN推理引擎如何通过数据内存重新排布进行内核优化,特别是针对WinoGrad卷积计算的优化方法,通过NC4HW4数据格式重排,有效利用了SIMD指令集特性,减少了cache miss,提高了计算效率。
27 3
|
13天前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
14天前
|
机器学习/深度学习 人工智能 算法
【AI系统】内存分配算法
本文探讨了AI编译器前端优化中的内存分配问题,涵盖模型与硬件内存的发展、内存划分及其优化算法。文章首先分析了神经网络模型对NPU内存需求的增长趋势,随后详细介绍了静态与动态内存的概念及其实现方式,最后重点讨论了几种节省内存的算法,如空间换内存、计算换内存、模型压缩和内存复用等,旨在提高内存使用效率,减少碎片化,提升模型训练和推理的性能。
32 1
|
28天前
|
监控 Java Android开发
深入探讨Android系统的内存管理机制
本文将深入分析Android系统的内存管理机制,包括其内存分配、回收策略以及常见的内存泄漏问题。通过对这些方面的详细讨论,读者可以更好地理解Android系统如何高效地管理内存资源,从而提高应用程序的性能和稳定性。
62 16
|
18天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
48 1
|
20天前
|
JavaScript
如何使用内存快照分析工具来分析Node.js应用的内存问题?
需要注意的是,不同的内存快照分析工具可能具有不同的功能和操作方式,在使用时需要根据具体工具的说明和特点进行灵活运用。
39 3
|
28天前
|
存储 缓存 C语言
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
42 3
|
28天前
|
Linux
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
|
1月前
|
开发框架 监控 .NET
【Azure App Service】部署在App Service上的.NET应用内存消耗不能超过2GB的情况分析
x64 dotnet runtime is not installed on the app service by default. Since we had the app service running in x64, it was proxying the request to a 32 bit dotnet process which was throwing an OutOfMemoryException with requests >100MB. It worked on the IaaS servers because we had the x64 runtime install