Android 中的 Dalvik Heap 和 Native Heap

Android程序为什么容易出现OOM

这个是因为 Android系统对 dalvik 的 vm heapsize 作了硬性限制,当 java 进程申请的 java 空间超过阈值时,就会抛出OOM异常(这个阈值可以是48 M、24 M、16 M等,视机型而定),可以通过adb shell getprop 或者 grep dalvik.vm.heapgrowthlimit 查看此值。

也就是说,程序发生 OMM 并不表示 RAM 不足,而是因为程序申请的 java heap 对象超过了 dalvik vm heapgrowthlimit。也就是说,在 RAM 充足的情况下,也可能发生 OOM 。

这样的设计似乎有些不合理,但是 Google 为什么这样做呢?这样设计的目的是为了让 Android 系统能同时让比较多的进程常驻内存,这样程序启动时就不用每次都重新加载到内存,能够给用户更快的响应。迫使每个应用程序使用较小的内存,移动设备非常有限的RAM就能使比较多的app常驻其中。

进程内存空间和 RAM 之间的关系

进程的内存空间只是虚拟内存(或者叫作逻辑内存),而程序的运行需要的是实实在在的内存,即物理内存(RAM)。在必要时,操作系统会将程序运行中申请的内存(虚拟内存)映射到RAM,让进程能够使用物理内存。

Android中的进程

native进程:采用C/C++实现,不包含dalvik实例的linux进程,/system/bin/目录下面的程序文件运行后都是以native进程形式存在的。

java进程:实例化了 dalvik 虚拟机实例的 linux 进程,进程的入口 main 函数为 java 函数。dalvik 虚拟机实例的宿主进程是fork()调用创建的 linux 进程,所以每一个 android 上的 java 进程实际上就是一个 linux 进程,只是进程中多了一个 dalvik 虚拟机实例。因此,java 进程的内存分配比 native 进程复杂。Android 系统中的应用程序基本都是 java 进程,如桌面、电话、联系人、状态栏等等。

解释一些字段的意思:

  • VSS- Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
  • RSS- Resident Set Size 实际使用物理内存(包含共享库占用的内存)

  • PSS- Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
  • USS- Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)

一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS

Android中进程的堆内存

进程空间中的heap空间是我们需要重点关注的,heap空间完全由程序员控制,我们使用的malloc、C++ new 和 java new所申请的空间都是heap空间, C/C++ 申请的内存空间在 native heap 中,而 java 申请的内存空间则在 dalvik heap中。

Android如何应对RAM不足

java 程序发生 OMM 并不是表示 RAM 不足,如果 RAM 真的不足,会发生什么呢?这时 Android 的 memory killer 会起作用,当 RAM 所剩不多时,memory killer 会杀死一些优先级比较低的进程来释放物理内存,让高优先级程序得到更多的内存。

应用程序如何绕过dalvikvm heapsize的限制

创建子进程

创建一个新的进程,那么我们就可以把一些对象分配到新进程的heap上了,从而达到一个应用程序使用更多的内存的目的,当然,创建子进程会增加系统开销,而且并不是所有应用程序都适合这样做,视需求而定。

使用jni在native heap上申请空间

native heap的增长并不受dalvik vm heapsize的限制,只要RAM有剩余空间,程序员可以一直在native heap上申请空间,当然如果 RAM快耗尽,memory killer会杀进程释放RAM。大家使用一些软件时,有时候会闪退,就可能是软件在native层申请了比较多的内存导致的。

相关推荐

深入浅出腾讯云CDN:缓存篇

缓存系统在游戏业务中的特异性

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

王浩的专栏

1 篇文章1 人订阅

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大史住在大前端

webpack4.0各个击破(4)—— Javascript & splitChunk

javascript之所以需要打包合并,是因为模块化开发的存在。开发阶段我们需要将js文件分开写在很多零碎的文件中,方便调试和修改,但如果就这样上线,那首页的h...

713
来自专栏性能与架构

linux 实时监控进程状态 - pidstat

pidstat 命令用来监控所有进程的状态,如进程占用的 CPU、内存、IO 可以指定监控具体的进程ID、监控时间间隔等 执行 pidstat 命令,默认显示出...

2633
来自专栏cs

linux学习笔记四

进程(process)是程序实体运行的过程,是系统进行资源分配和调度的独立单位,或者说是一个程序在处理机上的一次执行活动。 区分一下进程和程序 ---- 1....

34714
来自专栏小狼的世界

Codeigniter中对核心类的扩展

Codeigniter框架提供了实现多个应用Application的方法,如参考资料[2]中描述的,这种方法实际上是在网站目录下存在多个入口文件和Applica...

612
来自专栏数据之美

Zookeeper 原理与实践

1、Zookeeper 的由来 在Hadoop生态系统中,许多项目的Logo都采用了动物,比如 Hadoop 和 Hive 采用了大象的形象,HBase 采用了...

3338
来自专栏IMWeb前端团队

使用Node.js实现一个简单的ZooKeeper客户端

什么是ZooKeeper Zookeeper 是一个分布式的、开源的协调服务,用在分布式应用程序中。它提出了一组简单的原语,分布式应用程序可以基于这些原语之上...

2010
来自专栏个人分享

kafka入门:简介、使用场景、设计原理、主要配置及集群搭建(转)

    Kafka is a distributed,partitioned,replicated commit logservice。它提供了类似于JMS的特...

1045
来自专栏腾讯IVWEB团队的专栏

使用 Node.js 实现一个简单的 ZooKeeper 客户端

Zookeeper 是一个分布式的、开源的协调服务,用在分布式应用程序中。它提出了一组简单的原语,分布式应用程序可以基于这些原语之上构建更高层的分布式服务用于实...

1.3K0
来自专栏Spark学习技巧

Mapreduce shuffle详解

Mapreduce shuffle详解 Mapreduce确保每个reducer的的输入都是按键排序的。系统执行排序的过程(即将map输出作为输入 传给redu...

2853
来自专栏IT技术精选文摘

浅析Nginx的工作模式及原理

(微信公众号:IT技术精选文摘, 微信号:ITHK01, 欢迎订阅) 同Apache http server的Perfork工作模型类似,Nginx也有mast...

2297

扫码关注云+社区