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

简介:
  回到前面BpMemoryHeap类中的assertMapped函数中,如果本BpMemoryHeap对象中的mHeapID等于-1,那么就说明这个BpMemoryHeap对象中的匿名共享内存还没准备就绪,因此,需要执行一次映射匿名共享内存的操作。
        在执行映射操作之作,先要看看在本进程中是否有其它映射到同一个MemoryHeapBase对象的BpMemoryHeap对象存在:
  1. sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());  
  2. sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));  
       这里的find_heap函数是BpMemoryHeap的成员函数,最终它调用了前面提到的全局变量gHeapCache来直正执行查找的操作:
  1. class BpMemoryHeap : public BpInterface<IMemoryHeap>  
  2. {     
  3. ......  
  4.   
  5. private:  
  6.     static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {  
  7.         return gHeapCache->find_heap(binder);  
  8.     }  
  9.   
  10.     ......  
  11. }  
        注意,这里通过find_heap函数得到BpMemoryHeap对象可能是和正在执行assertMapped函数中的BpMemoryHeap对象一样,也可能不一样,但是这没有关系,这两种情况的处理方式都是一样的,都是通过调用这个通过find_heap函数得到BpMemoryHeap对象的assertReallyMapped函数来进一步确认它内部的匿名共享内存是否已经映射到进程空间了:
  1. void BpMemoryHeap::assertReallyMapped() const  
  2. {  
  3.     if (mHeapId == -1) {  
  4.   
  5.         // remote call without mLock held, worse case scenario, we end up  
  6.         // calling transact() from multiple threads, but that's not a problem,  
  7.         // only mmap below must be in the critical section.  
  8.   
  9.         Parcel data, reply;  
  10.         data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());  
  11.         status_t err = remote()->transact(HEAP_ID, data, &reply);  
  12.         int parcel_fd = reply.readFileDescriptor();  
  13.         ssize_t size = reply.readInt32();  
  14.         uint32_t flags = reply.readInt32();  
  15.   
  16.         LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%ld, err=%d (%s)",  
  17.             asBinder().get(), parcel_fd, size, err, strerror(-err));  
  18.   
  19.         int fd = dup( parcel_fd );  
  20.         LOGE_IF(fd==-1, "cannot dup fd=%d, size=%ld, err=%d (%s)",  
  21.             parcel_fd, size, err, strerror(errno));  
  22.   
  23.         int access = PROT_READ;  
  24.         if (!(flags & READ_ONLY)) {  
  25.             access |= PROT_WRITE;  
  26.         }  
  27.   
  28.         Mutex::Autolock _l(mLock);  
  29.         if (mHeapId == -1) {  
  30.             mRealHeap = true;  
  31.             mBase = mmap(0, size, access, MAP_SHARED, fd, 0);  
  32.             if (mBase == MAP_FAILED) {  
  33.                 LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",  
  34.                     asBinder().get(), size, fd, strerror(errno));  
  35.                 close(fd);  
  36.             } else {  
  37.                 mSize = size;  
  38.                 mFlags = flags;  
  39.                 android_atomic_write(fd, &mHeapId);  
  40.             }  
  41.         }  
  42.     }  
  43. }  
        如果成员变量mHeapId的值为-1,就说明还没有把在Server端的MemoryHeapBase对象中的匿名共享内存映射到本进程空间来,于是,就通过一个Binder进程间调用把Server端的MemoryHeapBase对象中的匿名共享内存对象信息取回来:
  1. Parcel data, reply;  
  2. data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());  
  3. status_t err = remote()->transact(HEAP_ID, data, &reply);  
  4. int parcel_fd = reply.readFileDescriptor();  
  5. ssize_t size = reply.readInt32();  
  6. uint32_t flags = reply.readInt32();  
  7.   
  8. ......  
  9.   
  10. int fd = dup( parcel_fd );  
  11.           
  12. ......  
        取回来的信息包括MemoryHeapBase对象中的匿名共享内存在本进程中的文件描述符fd、大小size以及访问属性flags。如何把MemoryHeapBase对象中的匿名共享内存作为本进程的一个打开文件描述符,请参考前面一篇文章 Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析 。有了这个文件描述符fd后,就可以对它进行内存映射操作了:
  1. Mutex::Autolock _l(mLock);  
  2. if (mHeapId == -1) {  
  3.     mRealHeap = true;  
  4.     mBase = mmap(0, size, access, MAP_SHARED, fd, 0);  
  5.     if (mBase == MAP_FAILED) {  
  6.         LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",  
  7.             asBinder().get(), size, fd, strerror(errno));  
  8.         close(fd);  
  9.     } else {  
  10.         mSize = size;  
  11.         mFlags = flags;  
  12.         android_atomic_write(fd, &mHeapId);  
  13.     }  
  14. }  
        前面已经判断过mHeapId是否为-1了,这里为什么又要重新判断一次呢?这里因为,在上面执行Binder进程间调用的过程中,很有可能也有其它的线程也对这个BpMemoryHeap对象执行匿名共享内存映射的操作,因此,这里还要重新判断一下mHeapId的值是否为-1,如果是的话,就要执行匿名共享内存映射的操作了,这是通过调用mmap函数来进行的,这个函数我们前面在分析MemoryHeapBase类的实现时已经见过了。
 
        从assertReallyMapped函数返回到assertMapped函数中:
  1. if (heap->mBase != MAP_FAILED) {  
  2.     Mutex::Autolock _l(mLock);  
  3.     if (mHeapId == -1) {  
  4.         mBase   = heap->mBase;  
  5.         mSize   = heap->mSize;  
  6.         android_atomic_write( dup( heap->mHeapId ), &mHeapId );  
  7.     }  
  8. else {  
  9.     // something went wrong  
  10.     free_heap(binder);  
  11. }  
        如果heap->mBase的值不为MAP_FAILED,就说明这个heap对象中的匿名共享内存已经映射好了。进入到里面的if语句,如果本BpMemoryHeap对象中的mHeap成员变量的值不等待-1,就说明前面通过find_heap函数得到的BpMemoryHeap对象和正在执行assertMapped函数的BpMemoryHeap对象是同一个对象了,因此,什么也不用做就可以返回了,否则的话,就要初始化一下本BpMemoryHeap对象的相关成员变量了:
  1. mBase   = heap->mBase;  
  2. mSize   = heap->mSize;  
  3. android_atomic_write( dup( heap->mHeapId ), &mHeapId );  
        注意,由于这块匿名共享内存已经在本进程中映射好了,因此,这里不需要再执行一次mmap操作,只需要把heap对象的相应成员变量的值拷贝过来就行了,不过对于文件描述符,需要通过dup函数来复制一个。
 
        这样,BpMemoryHeap对象中的匿名共享内存就准备就绪了,可以通过使用的它mBase成员变量来直接访问这块匿名共享内存。
        至此,MemoryHeapBase类的实现就分析完了,下面我们继续分析MemoryBase类的实现。




本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966904,如需转载请自行联系原作者
目录
相关文章
|
8月前
|
存储 弹性计算 缓存
阿里云服务器ECS经济型、通用算力、计算型、通用和内存型选购指南及使用场景分析
本文详细解析阿里云ECS服务器的经济型、通用算力型、计算型、通用型和内存型实例的区别及适用场景,涵盖性能特点、配置比例与实际应用,助你根据业务需求精准选型,提升资源利用率并降低成本。
543 3
|
4月前
|
设计模式 缓存 Java
【JUC】(4)从JMM内存模型的角度来分析CAS并发性问题
本篇文章将从JMM内存模型的角度来分析CAS并发性问题; 内容包含:介绍JMM、CAS、balking犹豫模式、二次检查锁、指令重排问题
152 1
|
6月前
|
缓存 监控 Linux
CentOS系统如何查看当前内存容量。
以上方法都不需要特殊软件或者复杂配置即可执行,在CentOS或其他Linux发行版中都适合运行,并且它们各自透露出不同角度对待问题解答方式:从简单快速到深入详尽;从用户态到核心态;从操作层数到硬件层数;满足不同用户需求与偏好。
454 8
|
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
|
7月前
|
存储 缓存 监控
手动清除Ubuntu系统中的内存缓存的步骤
此外,只有系统管理员或具有适当权限的用户才能执行这些命令,因为这涉及到系统级的操作。普通用户尝试执行这些操作会因权限不足而失败。
1362 22
|
11月前
|
监控 Linux Python
Linux系统资源管理:多角度查看内存使用情况。
要知道,透过内存管理的窗口,我们可以洞察到Linux系统运行的真实身姿,如同解剖学家透过微观镜,洞察生命的奥秘。记住,不要惧怕那些高深的命令和参数,他们只是你掌握系统"魔法棒"的钥匙,熟练掌握后,你就可以骄傲地说:Linux,我来了!
383 27
|
11月前
|
存储 Java
课时4:对象内存分析
接下来对对象实例化操作展开初步分析。在整个课程学习中,对象使用环节往往是最棘手的问题所在。
107 4
|
11月前
|
Java 编译器 Go
go的内存逃逸分析
内存逃逸分析是Go编译器在编译期间根据变量的类型和作用域,确定变量分配在堆上还是栈上的过程。如果变量需要分配在堆上,则称作内存逃逸。Go语言有自动内存管理(GC),开发者无需手动释放内存,但编译器需准确分配内存以优化性能。常见的内存逃逸场景包括返回局部变量的指针、使用`interface{}`动态类型、栈空间不足和闭包等。内存逃逸会影响性能,因为操作堆比栈慢,且增加GC压力。合理使用内存逃逸分析工具(如`-gcflags=-m`)有助于编写高效代码。
239 2
|
机器学习/深度学习 人工智能 缓存
【AI系统】推理内存布局
本文介绍了CPU和GPU的基础内存知识,NCHWX内存排布格式,以及MNN推理引擎如何通过数据内存重新排布进行内核优化,特别是针对WinoGrad卷积计算的优化方法,通过NC4HW4数据格式重排,有效利用了SIMD指令集特性,减少了cache miss,提高了计算效率。
544 3