前言

无论是从资源使用的角度,还是从发现内存泄漏问题的角度来看,在性能测试或者系统的稳定性测试中,内存的使用情况是一个很重要的监控点。为保证项目的质量前移,输入法内核测试小组的同学分配到了一个新的任务,就是在andriod平台上监测输入法内核 native 代码的内存使用情况。

为了完成这个任务,我们先将任务拆解成重要的几步:

1. 了解 andriod 平台的程序与内存

2. 了解 native代码在andriod平台上是如何进行内存分配的

3.  根据2步骤,方法调研,监测native代码内存使用情况

完成任务前先了解一些基本小知识:

堆和栈:

Stack空间(进栈和出栈)由操作系统控制,其中主要存储函数地址、函数参数、局部变量等等,所以Stack空间不需要很大,一般为几mb大小。

Heap空间 由程序控制,程序员可以使用malloc、new、free、delete等函数调用来操作这片地址空间。heap为程序完成各种复杂任务提供内存空间,所以空间比较大,一般为几百mb到几gb。正是因为heap空间由程序员管理,所以容易出现使用不当导致严重问题,我们重点关注的也是这部分由程序员控制的内存空间。‍

正文

1

了解 andriod 平台的程序与内存

在Android里,程序内存被分为2部分:native进程和:dalvik进程

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

java进程(dalvik进程):是实例化了dalvik虚拟机实例的linux进程,进程的入口main函数为java函数。dalvik虚拟机实例的宿主进程是fork()系统调用创建的linux进程,所以每一个android上的java进程实际上就是一个linux进程,只是进程中多了一个dalvik虚拟机实例。

使用命令 adb shell prorank 可以看到

/system/bin/* 下面的是native进程,桌面、电话、联系人、状态栏等等都是java进程。

在这里不详细描述,native进程和java进程究竟如何分配的内存,有兴趣的同学可以自行搜索,我们只重点关注两种进程空间中的heap空间的分配情况。heap空间完全由程序员控制分配,一共可分为dalvik heap 和 native heap两种,我们使用的malloc、c++ new和java new所申请的空间都是heap空间, c/c++申请的内存空间在native heap中,而java申请的内存空间则在dalvik heap中。

2

了解 native代码在andriod上是如何进行内存分配的

根据以上,我们已经了解了 c/c++代码申请的内存空间在native heap中,而java代码申请的内存空间则在dalvik heap中,那么 native代码在andriod平台上进行内存分配的这个过程是如何执行的呢,这就离不开一个概念JNI,什么是JNI:JNI是Java Native Interface的缩写,提供了若干API实现了java和其他语言的通信(主要是c&c++)。

在java代码中,java对象被存放在jvm的java heap中,由垃圾回收器自动回收就可以。

在JNI代码中,JNI与java的分配方式有所不同,JNI是java/其他语言交流的媒介。JNI提供了与java相对应的引用类型(如:jobject、jstring、jclass、jarray、jintArray等),以便native代码可以通过JNI函数访问到java对象。引用所指向的java对象通常就是存放在java heap,而native代码持有的引用是存放在native memory中。

举个例子,如下代码:

jstring jstr = env->NewStringUTF("Hello World!");

  1. jstring类型是JNI提供的,对应于java的string类型。

  2. JNI函数NewStringUTF()用于构造一个string对象,该对象存放在java heap中,同时返回了一个jstring类型的引用。

  3. string对象的引用保存在jstr中,jstr是native的一个局部变量,存放在native memory中。‍

在native代码中,根据下图jvm的内存模型,可以看到本地库接口是在在jvm运行时数据区域之外。因此,调用c/c++写的库,malloc 分配的内存是按照c/c++的规范去操作内存,内存是从native heap中分配的。

3

根据2步骤,方法调研,监测native代码内存使用情况

根据2步骤,我们可以知道,如果想在andriod平台监控native的内存占用情况,我们需要在native代码运行时监控native heap的分配情况。

使用命令adb shell dumpsys meminfo就可以达到以上需求:

一般实时输出的信息像这样:

在这里对主要字段进行解释:

横轴:

pss: proportional set size是内核计算的度量,代表整体的内存情况,它将内存共享考虑在内。系统会根据内存页中的其他进程使用的比例动态调整每个RAM内存页。

private dirty:进程独占的内存。也就是应用进程销毁时系统可以直接回收的内存容量。通常来说,“private dirty”内存是其最重要的部分,因为只被自己的进程使用。它只在内存中存储,因此不能做分页存储到外存。所有分配的dalvik堆和本地堆都是“private dirty”内存。pss/private dirty三列是读取了/proc/process-id/smaps文件获取的,可以通过adbshell cat /proc/process-id/smaps来查看。

private clean:包括该进程私有的干净的内存。

纵轴:

dalvik heap:应用中dalvik分配使用的内存。

native heap:应用中c/c++分配使用的内存。

.so / jar /apk /...mmap:c库 / java /apk /...代码占用的内存。

unknown:无法归类到其它项的内存页。目前,这主要包含大部分的本地分配,就是那些在工具收集数据时由于地址空间布局随机化不能被计算在内的部分。

total:进程总使用的实际使用内存(PSS),是上面所有PSS项的总和。它表明了进程总的内存使用量,可以直接用来和其它进程或总的可以内存进行比较。

结论

使用命令adb shell dumpsys meminfo 监控native heap只能大致分析native 代码的使用情况,与真实使用存在一定的误差,如果对native内存使用有着非常高精确的需求,可以尝试抓取一个带有调用堆栈地址的native heap usage, 有了堆栈地址, 我们可以通过arm-linux-androideabi-addr2line.exe把地址翻译成函数名. 尝试将堆栈地址合并进行内存的累加统计,可以精确的看到函数的内存占用情况,不过小编还没有尝试过这种方法,如果有尝试过的同学,欢迎在评论里和大家分享经验,不胜感谢~

解密native代码的内存使用的更多相关文章

  1. Ngen生成Native代码实战及优缺点分析

    先科普一下,.Net是一个用于Windows的托管代码模型,用于高效构建具有视觉上引人注目的用户体验的应用程序.但这个模型生成的代码并非可执行代码,而是由.Net公共语言运行库环境执行的IL代码.所以 ...

  2. Android Native 代码NDK开发学习笔记

    引用:http://www.kunli.info/2011/08/21/android-native-code-study-note/ JNI,全称Java Native Interface,是用于让 ...

  3. Java实现MD5加密及解密的代码实例分享

    链接:http://www.jb51.net/article/86027.htm Java实现MD5加密及解密的代码实例分享 作者:厦门大学陈黎栋 字体:[增加 减小] 类型:转载 时间:2016-0 ...

  4. 彻底告别加解密模块代码拷贝-JCE核心Cpiher详解

    前提 javax.crypto.Cipher,翻译为密码,其实叫做密码器更加合适.Cipher是JCA(Java Cryptographic Extension,Java加密扩展)的核心,提供基于多种 ...

  5. Pythontutor:可视化代码在内存的执行过程

    http://www.pythontutor.com/visualize.html今天去问开发一个Python浅拷贝的问题,开发给了一个神器,可以可视化代码在内存的执行过程,一看即懂,太NB了!~真是 ...

  6. Java native代码编译步骤简书

    Java native代码编译步骤简书 目的:防止java代码反编译获取密码算法 (1)编写实现类com.godlet.PasswordAuth.java (2)编译java代码javac Passw ...

  7. c++ 汇编代码看内存分配

    汇编代码看内存分配 (1). 程序运行时分为存储区域分为 存储区域 存储内容 extra 代码区 存放代码指令,包括除字符串常量的字面值 静态存储区 存放静态变量和全局变量 执行main之前就分配好了 ...

  8. 如何用Java编写一段代码引发内存泄露

    本文来自StackOverflow问答网站的一个热门讨论:如何用Java编写一段会发生内存泄露的代码. Q:刚才我参加了面试,面试官问我如何写出会发生内存泄露的Java代码.这个问题我一点思路都没有, ...

  9. 怎样用Java编写一段代码引发内存泄露

    通过下面步骤能够非常easy产生内存泄露(程序代码不能訪问到某些对象,可是它们仍然保存在内存中): 应用程序创建一个长时间执行的线程(或者使用线程池,会更快地发生内存泄露). 线程通过某个类载入器(能 ...

随机推荐

  1. HugeGraph图数据库--测试

    2018年百度的HugeGraph.实现了Apache TinkerPop3框架及完全兼容Gremlin查询语言.开源项目https://github.com/hugegraph HugeGraph典 ...

  2. jQuery-Ajax请求Json数据并加载在前端页面,附视频教程讲解!

    Ajax技术应用广泛,这种异步加载技术,无需刷新网页即可更新网站内容,全局或者局部均可,所以大家应该学会这种技巧,把技术用上来. 创建demo.json文件,用来做数据源: {     "t ...

  3. 远程桌面按键失效变成快捷键(远程桌面连接时会自动按下win键)

    三个电脑快捷键 (无意中学会三个快捷键了.....)win + L 锁屏win + D 切换到桌面win + F 搜索 在使用远程桌面连接Windows 2008操作系统,发现一个很烦的问题,经常发现 ...

  4. Microsoft SQL Server(sql server 关系型数据库管理系统)

    sql server一般指Microsoft SQL Server 关系型数据库管理系统 Microsoft SQL Server 是一个全面的数据库平台,使用集成的商业智能 (BI)工具提供了企业级 ...

  5. 环境变量(windows下tomcat问题);shh连接虚拟机网络配置

    环境变量(windows下tomcat问题) 有tomcat有jdk 再配置环境变量:参考 提示:若选择“用户变量”,则本次配置的变量只对该用户有效          若选择“系统变量”,则对所有用户 ...

  6. Alex and Number

    Alex and Number 时间限制: 1 Sec  内存限制: 128 MB提交: 69  解决: 12[提交][状态] 题目描述 Alex love Number theory. Today ...

  7. 父元素a标签的href默认行为以及子元素绑定的click事件的响应之间存在影响

    原文地址 背景 开发过程中遇到问题,简单写个demo 运行环境为Chrome 68 描述一下这个问题,当a标签内部存在嵌套时, 父元素a标签的href默认行为以及子元素绑定的click事件的响应之间存 ...

  8. 从xxxx检测到有潜在危险的 Request.Form 提示黄页

    相信很多朋友都遇到过"从客户端xxxxxx"检测到有潜在危险的 Request.Form 然后给一个黄页提示.然后检测代码又找不到错误的代码提示. 原因:是因为在页面里边使用了富文 ...

  9. 关于C++中nothrow的某某某

    前言 在学习C++中new的种种用法时,在operator new的其中一个重载版本中看一个参数nothrow,想弄清楚到底是什么意思?nothrow顾名思义,就是不抛出的意思嘛!不抛出啥,在C++中 ...

  10. 用 Flask 来写个轻博客 (31) — 使用 Flask-Admin 实现 FileSystem 管理

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 编写 FileSystem Admin 页面 Flask-A ...