中调用如下:module_init(ashmem_init);下面分析下ashmem_init的函数实现:static int __init ashmem_init(void){ int ret; = misc_register(&ashmem_misc); register_shrinker(&ashmem_shrinker); printk(KERN_INFO "ashmem: Ashmem的设备节点是dev/ashmem? 另外有全局变量ashmem_lru_list,以Lru的算法存储,存储所有的unpinned ashmem_range,用于在内存紧张时按照Lru释放部分ashmem_range以回收内存。 上文介绍过,ashmem_unpin_region最终会触发Ashmem的ashmem_unpin,于是range[0,4096]被加入到全局的ashmem_lru_list链表。
答案就是匿名共享内存(Anonymous Shared Memory-Ashmem) ? 图片来源于网上 为了学习匿名共享内存的使用,我们来写一个demo。
Ashmem Android系统的匿名共享内存Ashmem驱动程序利用了Linux的共享内存子系统导出的接口来实现。 在Android系统中,匿名共享内存也是进程间通信方式的一种。 源码路径:system/core/libcutils/ashmem-dev.c android源码中,ashmem的实现: 打开共享内存: ---- /* * ashmem_create_region __ashmem_open函数的实现如下: /* logistics of getting file descriptor for ashmem */ static int __ashmem_open_locked int ashmem_valid(int fd) { return __ashmem_is_ashmem(fd, 0) >= 0; } 除此之外,源码中还提供了几个接口函数: 1. 获取大小 int ashmem_get_size_region(int fd) { int ret = __ashmem_is_ashmem(fd, 1); if (ret < 0) {
__ashmem_open_locked 方法,如下: #define ASHMEM_DEVICE "/dev/ashmem" //Ashmem 设备驱动 static int __ashmem_open_locked return fd; } 在 __ashmem_open_locked 方法中调用了 open() 系统调用,和 ioctl 一样,对应到 Ashmem 设备驱动函数了,即 「ashmem_open」 通过上面的分析知道 Ashmem 驱动的 ashmem_open 函数是由 SharedMemory 的 create 方法触发一步一步调用到的,期间还调用了 ashmem_ioctl 函数。 : 通过 fd 可以找到所属设备,也就是 Ashmem 设备 调用 Ashmem 设备的 ashmem_mmap 驱动函数 关键代码如下: if(file){ ... 也就是注册的 Ashmem 设备描述,至此便是 ashmem_mmap 驱动函数的调用过程。
| 导语上文介绍了Android中提供的Ashmem(匿名内存)。Ashmem以驱动的形式运行在内核。 应用层如果需要使用Ashmem,可以直接打开Ashmem驱动并和驱动进行交互,也可以使用Android为我们提供的基于Ashmem驱动的函数库(更推荐使用这个)。 Ashmem函数库函数库代码位于://函数库代码ashmem.hashmem-dev.c提供了5个函数以供应用层使用:int ashmem_create_region(const char *name, fd)函数库代码很简单,打开Ashmem驱动,并与之进行交互,以ashmem_create_region为例,代码如下:int ashmem_create_region(const char *name _ashmem_open_locked(){ //ASHMEM_DEVICE为/dev/ashmem,打开Ashmem设备 int fd = TEMP_FAILURE_RETRY(open(
ashmem的使用流程如下: 1.ashmem_create_region创建匿名共享内存区域,本质是调用open系统调用 2.ioctl设置共享内存的名字和大小,设置的名字为/dev/ashmem/ 那么ashmem和Binder有什么区别呢? Binder的mmap时候已经通过伙伴系统绑定了物理页和虚拟内存之间的联系,而Ashmem则是通过缺页中断,调用相关的函数才进行绑定。 换句话说Ashmem是按需加载,而Binder则是一开始就通过mmap就分配好。 Ashmem就是打通一块大的内存通道方便进程之间通信大数据。
add-apt-repository ppa:morphis/anbox-support sudo apt install -y anbox-modules-dkms sudo modprobe ashmem_linux anbox-support $ sudo apt update $ sudo apt install anbox-modules-dkms 这些将PPA添加到您的系统并安装anbox-modules-dkms 包含ashmem $ sudo modprobe ashmem_linux $ sudo modprobe binder_linux 现在,您的系统/dev目录中应该有两个新节点: $ ls -1 /dev/{ashmem ,binder} /dev/ashmem /dev/binder 安装Anbox snap 安装Anbox snap非常简单: $ snap install --devmode --beta anbox
Fresco在4.X的机器的内存性能很好,Bitmap存在Ashmem(匿名共享内存)层里面的,对应用的内存缓存的压力不大。 4.X系统的Fresco ? 安卓系统的Ashmem层这里不做过多介绍,我们来看下缓存到Ashmem最后一个JAVA函数。 inPurgeable这个属性标识这个Bitmap是否是可清除的,设置为true之后,该系统会自动把Bitmap存储在Ashmem中, 当系统存储不足的时候会被回收,等到需要的时候,会在主线程重新进行解码 5.X以上系统的Fresco 然而purgeable bitmap引起主线程卡顿的这一缺陷最终使得谷歌在5.0以上的系统废弃了它,所以Fresco在5.0以上系统再也没法使用Ashmem层了,Bitmap
在android源码的驱动目录下,一般会有共享内存的相关实现源码,目录是:kernel\drivers\staging\android\ashmem.c。 a,命名为mysharememory_a代码如下: #include <fcntl.h> #include <stdio.h> #include <string.h> #include <linux/ashmem.h IPCThreadState.h> #include <binder/Parcel.h> #include <binder/IInterface.h> #define DEVASHMEM "/dev/ashmem 3.2 mysharememory_b代码如下: #include <fcntl.h> #include <stdio.h> #include <string.h> #include <linux/ashmem.h IPCThreadState.h> #include <binder/Parcel.h> #include <binder/IInterface.h> #define DEVASHMEM "/dev/ashmem
创建一个共享内存 int ashmemFd = ashmem_create_region(ashmemName.string(), size); if (ashmemFd < 0) { result = -errno; } else { //设置匿名共享内存可读可写 result = ashmem_set_prot_region( 这样子看来Cursor的大小是不受限制的,不懂匿名共享内存的可以先看一下[006]匿名共享内存(Ashmem)的使用 其实在Android Framework中对此有一定的限制,请注意在CursorWindow fd int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); if (result < 0) { BLOB_ASHMEM_MUTABLE : BLOB_ASHMEM_IMMUTABLE); if (!
它的基本原理是通过在Linux内核中安装Android所需要的内核模块(如:binder、ashmem等),然后运行一个Android容器而实现的。 crw-rw-rw- 1 root root 511, 0 7月 24 17:16 bindercrw-rw-rw- 1 root root 10, 58 7月 24 17:16 ashmem 如果没有看到可以尝试以下方法来手动加载:$ sudo insmod ashmem_linux$ sudo insmod binder_linux如果加载失败可以试下重启电脑后再加载。
创建 ashmemfd.reset( ashmem_create_region(debug_friendly_name.c_str(), page_aligned_byte_count)); // ---- PS: 关于Android 的ashmem可以阅读 Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析(http://blog.csdn.net /luoshengyang/article/details/6664554) 技术内幕:Android对Linux内核的增强 Ashmem(http://www.jmpcrash.com/? p=315) Android Kernel Features(https://elinux.org/Android_Kernel_Features#ashmem) ---- 至此,代码片段4就分析完了, OutOfMemoryError "pthread_create (1040KB stack) failed: Out of memory" 对于堆栈B 在上文提到的代码片段中: fd.Reset(ashmem_create_region
系统是会将allowFds设置为true,运行带fd描述字符的,当传递数据的时候,首先会判断当前数据是否小于16K,小于16KB的时候会直接使用Binder的缓存空间,而当大于16KB的时候,则开辟一个ashmem ,映射出一块内存,该数据会保存到ashmem中,在Intent中之写入一个fd的文件描述符,这样即使传输的数据再大,Intent中传输的也只是该资源的文件描述符。 而ashmem就是利用了共享内存,在发送端和接收端之间映射同一块内存,无需多次拷贝,提高了数据传输的性能。
Framework性能调优• Binder通信协议压缩算法改造 • 跨进程内存共享池设计(Ashmem魔改) 3. uint32_t flags)override{ if (data.dataSize() > 1024 * 1024) { // 启用Ashmem 共享内存通道 int fd = ashmem_create_region("large_buffer", dataSize); void* ptr
性能拐点:传输2MB位图时,Ashmem方案比直接Binder快4倍 优化方案: // 使用Ashmem传递大图 Bitmap bitmap = BitmapFactory.decodeFile(path
文件描述符可以跨进程传递; Android中哪里用到 Android中涉及到进程之间大数据量传输的主要就是图像相关的传输; 这里主要以MemoryFile为例, 这是Android的一个工具类, 封装了内存共享机制Ashmem ,也就是匿名共享内存; MemoryFile是android在最开始就引入的一套框架,其内部实际上是封装了android特有的内存共享机制Ashmem匿名共享内存,简单来说,Ashmem在Android 内核中是被注册成一个特殊的字符设备,Ashmem驱动通过在内核的一个自定义slab缓冲区中初始化一段内存区域,然后通过mmap把申请的内存映射到用户的进程空间中(通过tmpfs),这样子就可以在用户进程中使用这里申请的内存了
前文Android匿名共享内存(Ashmem)原理分析了匿名共享内存,它最主要的作用就是View视图绘制,Android视图是按照一帧一帧显示到屏幕的,而每一帧都会占用一定的存储空间,通过Ashmem机制 APP与SurfaceFlinger共享绘图数据,提高图形处理性能,本文就看Android是怎么利用Ashmem分配及绘制的: View视图内存的分配 前文Window添加流程中描述了:在添加窗口的时候 这里我们关心的是allocate函数,先分析普通图形缓冲区的分配,它最终会调用gralloc_alloc_buffer()利用匿名共享内存进行分配,之前的文章Android匿名共享内存(Ashmem)原理分析了 int err = 0; int fd = -1; size = roundUpToPageSize(size); // 创建共享内存,并且设定名字跟size fd = ashmem_create_region if (err == 0) { *pHandle = hnd; } } return err; } mapBuffer会进一步调用ashmem
听起来很美好,但该项目已于2023年停止更新,究其原因,可能是兼容性差,依赖非标准内核模块 binder (进程间通信)和 ashmem (共享内存),显卡兼容性也不好,很多应用只是那能用,但跑起来存在诸多问题 内核需启用 binder 、 ashmem 等模块,建议使用 Linux 5.4+ 版本。
mPixelStorage.external.address, mPixelStorage.external.context); break; case PixelStorageType::Ashmem : // mmap ashmem 内存(用于跨进程传递 Bitmap,例如 Notification) munmap(mPixelStorage.ashmem.address , mPixelStorage.ashmem.size); close(mPixelStorage.ashmem.fd); break; case PixelStorageType : // mmap ashmem 内存(用于跨进程传递 Bitmap,例如 Notification) munmap(mPixelStorage.ashmem.address , mPixelStorage.ashmem.size); close(mPixelStorage.ashmem.fd); break; case PixelStorageType
在5.0以下系统,Fresco将图片放到一个特别的内存区域(Ashmem区)。当然,在图片不显示的时候,占用的内存会自动被释放。这会使得APP更加流畅,减少因图片内存占用而引发的OOM。 因为在5.0系统以后系统默认就是存储在Ashmem区了。