如何偷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中的GingerbreadPurgeableDecoderKitKatPurgeableDecoder,Fresco在decode图片的时候会在4.4和4.4以下的系统中分别使用这两个不同的decoder

从这个地方可以看出来,使用MemoryFile,在4.4以下的系统当中,可以帮我们的app额外"偷"一些内存,并且可以不计入app的内存当中

Summary

这里主要是简单介绍了MemoryFile的基本原理和用法,并且阐述了一个MemoryFile中一个可以帮助开发者"偷"内存的地方,这个是一个非常trickly的方法,虽然4.4以下使用这块的内存并不计入进程当中,但是并不推荐大量使用,因为当设置了allowPurging为false的时候,这个对应的Ashmem内存区域是被"pin"了,那么在android系统内存不足的时候,是不能够把这段内存区域回收的,如果长时间没有释放的话,这样子相当于无端端占用了大量手机内存而又无法回收,那对系统的稳定性肯定会造成影响

References

  1. Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析
  2. Android Kernel Features(Ashmem)
时间: 2024-12-20 17:07:58

如何偷Android的内存-Tricking Android MemoryFile的相关文章

如何「偷」Android 的内存?

之前在做一个内存优化的时候,使用到了MemoryFile,由此发现了MemoryFile的一些特性以及一个非常trickly的使用方法,因此在这里记录一下 What is it MemoryFile是android在最开始就引入的一套框架,其内部实际上是封装了android特有的内存共享机制Ashmem匿名共享内存,简单来说,Ashmem在Android内核中是被注册成一个特殊的字符设备,Ashmem驱动通过在内核的一个自定义slab缓冲区中初始化一段内存区域,然后通过mmap把申请的内存映射到

Android的内存优化

腾讯公司在五月三十一日开展[腾讯Bugly移动开发者沙龙]大会,大会上面叶方正老师讲解了 关于Android的内存优化的问题,不过我感觉叶老师更多的站在了测试的角度上去解释了这一方面,叶老师给我们介绍了很多的工具去测试Android应用在各种情况下的内存占用情况,不过好像对我们开发的帮助并不是特别的大.我在这里总结叶老师所说的重点和自己对内存优化的一些理解,希望能够对大家有所帮助. Android应用优化主要集中在内存和UI流畅度上,从内存占用与泄露.UI流畅度的帧数和响应时间到IO的阻塞式响应

Android学习笔记_78_ Android开发中使用软引用和弱引用防止内存溢出

在<Effective Java 2nd Edition>中,第6条"消除过期的对象引用"提到,虽然Java有 垃圾回收机制,但是只要是自己管理的内存,就应该警惕内存泄露的问题,例如的对象池.缓存中的过期对象都有可能引发内存泄露的问题.书中还提到可以用 WeakHashMap来作为缓存的容器可以有效解决这一问题.之前也确实遇到过类似问题,但是没有接触过"弱引用"相关的问题,于是查阅了一些资料. <Java 理论与实践: 用弱引用堵住内存泄漏>

无废话Android之android下junit测试框架配置、保存文件到手机内存、android下文件访问的权限、保存文件到SD卡、获取SD卡大小、使用SharedPreferences进行数据存储、使用Pull解析器操作XML文件、android下操作sqlite数据库和事务(2)

1.android下junit测试框架配置 单元测试需要在手机中进行安装测试 (1).在清单文件中manifest节点下配置如下节点 <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.example.demo1" /> 上面targetPackage指定的包要和应用的package相同. (2)在清单文件中ap

Android dumpsys 内存分析

研究了Mat和Heap的分析方法之后,尝试用其他的方式来分析下,Androiddumpsys 的方式来看下结果. 如何得出数据的操作就不说了,网上太多了,只看数据来进行分析. 如图1,启动的时候的情况 执行三次怀疑有泄露的功能之后的数据 再执行三次 再执行三次 数据分析: Native 数据代表的是JNI层的数据,从mallinfo usmblks 获得 DalviK 数据代表的是Java层的数据,从Runtime Totalmemory获得 Size 代表是能获得的最大的数据 Alloc代表的

Android清理设备内存详细完整示例(一)

MainActivity如下: package come.on; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; i

Android高效内存之让你的图片省内存

Android高效内存之让你的图片省内存 在做内存优化的时候,我们发现除了解决内存泄露问题,剩下的就只有想办法减少真实的内存占用.而在App中,大部分内存可能被我们图片占用了,所以减少图片的内存占用可以带来直接的效果. 一.一张图片到底占用多少内存 我们先假设我们有一张图片是600 * 800像素的,图片磁盘占用空间大小假设是 100KB. 图片内存大小跟磁盘占用空间大小有什么关系? 磁盘占用空间的大小不是图片占用内存的大小,磁盘占用空间是在磁盘上存储图片需要的一个空间大小,内存大小是加载到内存

80.Android之内存管理

转载:http://www.jianshu.com/p/9fb0a795da93 1. Android中的内存 1.1 Android中的垃圾回收机制 Android 平台最吸引开发者的一个特性:有垃圾回收机制,无需手动管理内存,Android 系统会自动跟踪所有的对象,并释放那些不再被使用的对象 Young Generation 新生代 大多数新建对象都位于Eden(伊甸园)区 当Eden区被对象填满时,就会执行Minor GC(轻量GC).并把所有存活下来的对象转移到其中一个survivor

Android App 内存泄露之Thread

Thread 内存泄露 线程也是造成内存泄露的一个重要的源头.线程产生内存泄露的主要原因在于线程生命周期的不可控. 1.看一下下面是否存在问题 <span style="white-space:pre"> </span>/** * * @version 1.0.0 * @author Abay Zhuang <br/> * Create at 2014-7-17 */ public class ThreadActivity extends Activ