如何偷Android的内存-Tricking Android MemoryFile
之前在做一个内存优化的时候,使用到了MemoryFile,由此发现了MemoryFile的一些特性以及一个非常trickly的使用方法,因此在这里记录一下
What is it
MemoryFile是android在最开始就引入的一套框架,其内部实际上是封装了android特有的内存共享机制Ashmem匿名共享内存,简单来说,Ashmem在Android内核中是被注册成一个特殊的字符设备,Ashmem驱动通过在内核的一个自定义slab缓冲区中初始化一段内存区域,然后通过mmap把申请的内存映射到用户的进程空间中(通过tmpfs),这样子就可以在用户进程中使用这里申请的内存了,另外,Ashmem的一个特性就是可以在系统内存不足的时候,回收掉被标记为"unpin"的内存,这个后面会讲到,另外,MemoryFile也可以通过Binder跨进程调用来让两个进程共享一段内存区域。由于整个申请内存的过程并不再Java层上,可以很明显的看出使用MemoryFile申请的内存实际上是并不会占用Java堆内存的。
MemoryFile暴露出来的用户接口可以说跟他的名字一样,基本上跟我们平时的文件的读写基本一致,也可以使用InputStream和OutputStream来对其进行读写等操作:
MemoryFile memoryFile = new MemoryFile(null, inputStream.available());
memoryFile.allowPurging(false);
OutputStream outputStream = memoryFile.getOutputStream();
outputStream.write(1024);
上面可以看到allowPurging这个调用,这个就是之前说的"pin"和"unpin",在设置了allowPurging为false之后,这个MemoryFile对应的Ashmem就会被标记成"pin",那么即使在android系统内存不足的时候,也不会对这段内存进行回收。另外,由于Ashmem默认都是"unpin"的,因此申请的内存在某个时间点内都可能会被回收掉,这个时候是不可以再读写了
Tricks
MemoryFile是一个非常trickly的东西,由于并不占用Java堆内存,我们可以将一些对象用MemoryFile来保存起来避免GC,另外,这里可能android上有个BUG:
在4.4及其以上的系统中,如果在应用中使用了MemoryFile,那么在dumpsys meminfo的时候,可以看到多了一项Ashmem的值:

可以看出来虽然MemoryFile申请的内存不计入Java堆也不计入Native堆中,但是占用了Ashmem的内存,这个实际上是算入了app当前占用的内存当中
但是在4.4以下的机器中时,使用MemoryFile申请的内存居然是不算入app的内存中的:

而且这里我也算过,也是不算入Native Heap中的,另外,这个时候去系统设置里面看进程的内存占用,也可以看出来其实并没有计入Ashmem的内存的
这个应该是android的一个BUG,但是我搜了一下并没有搜到对应的issue,搞不好这里也可能是一个feature
而在大名鼎鼎的Fresco当中,他们也有用到这个bug来避免在decode bitmap的时候,将文件的字节读到Java堆中,使用了MemoryFile,并利用了这个BUG然这部分内存不算入app中,这里分别对应了Fresco中的GingerbreadPurgeableDecoder和KitKatPurgeableDecoder,Fresco在decode图片的时候会在4.4和4.4以下的系统中分别使用这两个不同的decoder
从这个地方可以看出来,使用MemoryFile,在4.4以下的系统当中,可以帮我们的app额外"偷"一些内存,并且可以不计入app的内存当中
Summary
这里主要是简单介绍了MemoryFile的基本原理和用法,并且阐述了一个MemoryFile中一个可以帮助开发者"偷"内存的地方,这个是一个非常trickly的方法,虽然4.4以下使用这块的内存并不计入进程当中,但是并不推荐大量使用,因为当设置了allowPurging为false的时候,这个对应的Ashmem内存区域是被"pin"了,那么在android系统内存不足的时候,是不能够把这段内存区域回收的,如果长时间没有释放的话,这样子相当于无端端占用了大量手机内存而又无法回收,那对系统的稳定性肯定会造成影响
References
如何偷Android的内存-Tricking Android MemoryFile的更多相关文章
- 关于Android 的内存泄露及分析
		
一. Android的内存机制Android的程序由Java语言编写,所以Android的内存管理与Java的内存管理相似.程序员通过new为对象分配内存,所有对象在java堆内分配空间:然而对象的释 ...
 - [轉]Android的内存泄漏和调试
		
一. Android的内存机制 Android的程序由Java语言编写,所以Android的内存管理与Java的内存管理相似.程序员通过new为对象分配内存,所有对象在java堆内分配空间:然而对象的 ...
 - 关于Android 的内存泄露及分析(转)
		
一. Android的内存机制Android的程序由Java语言编写,所以Android的内存管理与Java的内存管理相似.程序员通过new为对象分配内存,所有对象在java堆内分配空间:然而对象的释 ...
 - 关于android应用--内存的优化
		
以下内容为转载自网上,然后自己加工贴合到一块的: 原文地址:http://www.cnblogs.com/frydsh/archive/2012/12/09/2810601.html http://w ...
 - android防止内存溢出浅析
		
Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M.但是Android采用的是Java语言编写,所以在很大程度上,Android的内存机制等同于Java的内存机制,在刚开始开 ...
 - Android 操作系统的内存回收机制(转载)
		
Android 操作系统的内存回收机制(转载) Android APP 的运行环境 Android 是一款基于 Linux 内核,面向移动终端的操作系统.为适应其作为移动平台操作系统的特殊需要,谷歌对 ...
 - android应用内存使用情况
		
单个应用程序最大内存限制,超过这个值会产生OOM(内存溢出) 命令:adb shell ->dalvik.vm.heapgrowthlimit 应用启动后分配的初始内存 命令:adb shell ...
 - 80.Android之内存管理
		
转载:http://www.jianshu.com/p/9fb0a795da93 1. Android中的内存 1.1 Android中的垃圾回收机制 Android 平台最吸引开发者的一个特性:有垃 ...
 - 无废话Android之android下junit测试框架配置、保存文件到手机内存、android下文件访问的权限、保存文件到SD卡、获取SD卡大小、使用SharedPreferences进行数据存储、使用Pull解析器操作XML文件、android下操作sqlite数据库和事务(2)
		
1.android下junit测试框架配置 单元测试需要在手机中进行安装测试 (1).在清单文件中manifest节点下配置如下节点 <instrumentation android:name= ...
 
随机推荐
- .NET程序如何启动?
			
.net程序如何启动? .NET Framework在Windows平台顶部运行,这意味着.NET Framework必须使用 windows可以理解的技术来构建.首先,所有托管模块和程序集文件都必须 ...
 - Markdown编辑器推荐与语法教程--展示版
			
---恢复内容开始--- 前言 作为一名高级码农,怎能不知道Markdown的正确打开方式,Markdown现在可以说是无处不在,如果你还不知道简书中的代码块是怎么写出来的,小白无疑了.在此特别推荐一 ...
 - datasnap 上传/下载大文件(本Demo以图传片文件为例)
			
好久没写技术文了 datasnap传大流. 完整代码,同时感谢叶兄传流的指点,(只公开十天) 附:下面代码,转载请注明出处 ::code 服务端: function TServerMethods1.D ...
 - 项目中使用的图片上传方法,base64存本地
			
//生成健康报告 public function uploadJkbg(Request $r) { $data = $r->all(); $jkbg['jkbg_ctime'] = time() ...
 - 字节序(byte order)和位序(bit order)
			
字节序(byte order)和位序(bit order) 在网络编程中经常会提到网络字节序和主机序,也就是说当一个对象由多个字节组成的时候需要注意对象的多个字节在内存中的顺序. 以前我也基本只了 ...
 - mina2中IoHandler
			
IoHandler 当我们通过IoSession执行相关操作的时候,如写数据,这些事件会触发Mina框架抽象的IoService实例,从而调用Mina框架底层的相关组件进行处理.这时,配置的IoHan ...
 - spring data mongodb 操作
			
xml配置(mongo集群方式): <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=& ...
 - 《转载》ubuntu Sublime text 3 解决中文输入问题
			
其实,在这个文章之前,网上都有好多教程了.不知道是不是因为复制黏贴的传播太多,导致有些字符串的丢失,导致编译失败,so库文件无法载入,从而不能输入中文.折腾了许久之后,终于搞定了.记录下来,方便自己下 ...
 - (转)Docker - 使用 compose 编排服务
			
在园子里看到了这篇关于 compose 的文章,非常好!!转过来,先附上原文地址 http://www.cnblogs.com/52fhy/p/5991344.html ----- 入门示例 一般步骤 ...
 - ASP.NET页面传值加号变空格解决办法
			
只需要把欲传值进行编码 string EncodeId = Server.UrlEncode(id); 加号就变成了 % 2 B (中间无空格) 然后再传出去. Request.QueryStrin ...