版权声明:博文为原创内容,可以转载或引用,但须在明显位置标明原文作者和出处,未经同意不得擅自修改本文内容!博客地址:http://blog.csdn.net/luzhenrong45
RAM(random access memory),随机存取存储器,又称作“随机存储器”,对于Android设备来说,它还有一个更通俗常见的名称,叫 运行内存(简称运存)。一般来说,主流的Android设备有512M、768M、1G、2G等容量,现在高配手机都已经有3G、4G运行内存了。运行内存,通常是作为操作系统或其他正在运行程序的临时存储介质,也称作系统内存。就好比计算机中的内存条,如果内存条容量越大,计算机就有更多的内存来存储同时运行的任务,这样系统响应的速度也就越快,RAM在手机中就起到了这个作用。
拿RAM容量来说,其容量又分标称容量、实际容量和可用容量三种。标称容量即市场上一些手机厂商宣称的设备参数的容量,即运行内存1G、2G、4G这些。而事实上,实际容量肯定会比标称容量少一些,这其除了一些小量的损耗(算法、颗粒的不同)之外,部分手机还会被GPU占用一部分RAM。
1GB的设备看到的实际容量会是0.7 GB ~ 0.8 GB。而可用容量又会比实际容量再少一些,因为系统本身以及后台程序也需要占用一部分内存。
那么,怎么获取运行内存(RAM)的标称容量与实际容量呢?下面,以一块RK3188的Android开发板,来简单介绍一下。
我们知道,在linux下面,可以通过以下命令查看系统内存信息。
cat /proc/meminfo
Android内核是基于Linux的二次开发,当然也可以通过此命令进行内存参数的查看。例如:1 GB内存的Android设备情况如下所示:
以上信息中,我们在这里只需要重点关注 MemTotal 和 MemFree, 即RAM实际容量和RAM可用容量。
MemTotal: 运行内存实际容量,所有可用RAM大小(即物理内存减去一些预留位和内核的二进制代码大小),这个就是我们前面说的RAM实际容量了。
MemFree: 运行内存剩余容量,LowFree与HighFree的总和,留着未使用的内存,,这个就是我们前面说的RAM可用容量了。
因此,通过查看/proc/meminfo,便可获得设备运行内存的实际容量。
shell环境下,可以通过以下命令截取RAM实际容量:
cat /proc/meminfo |grep MemTotal|awk '{print $2" "$3}'
JAVA环境下:
/**
* 获取运行内存实际容量(KB)
*
*/
public static double getMemTotalSize() {
double memorySize = 1 * 1024 * 1024;//1GB;
BufferedReader bufferedReader = null;
File file = new File("/proc/meminfo");
if(file.exists()) {
try {
bufferedReader = new BufferedReader(new FileReader("/proc/meminfo"), 8192);
String line = null;
String content = null;
while ((line = bufferedReader.readLine()) != null) {
if(line.indexOf("MemTotal:") != -1) {
content = line.substring(line.indexOf("MemTotal:"));
memorySize = Double.parseDouble(content.replaceAll("\\D+", ""));
//Log.i(TAG, "get memory size: " + memorySize + " KB");
break;
}
}
} catch (IOException e) {
Log.w(TAG, "couldn't get memory size in " + MEMORY_PATH + ",memory size defaults to 1GB.");
memorySize = DEFAULT_MEMORY_SIZE_IN_KB;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}else {
Log.w(TAG, MEMORY_PATH + " not exist, memory size defaults to 1GB.");
memorySize=DEFAULT_MEMORY_SIZE_IN_KB;
}
return memorySize;
}
RAM可用容量也可以通过以上类似的方式进行获取。
另外说一下,Android本身也提供了标准API用于获取运存信息:
那么,RAM 标称容量呢,比如设备厂商宣称的 1GB, 2GB这些参数,又该如何获取?查找了一番,发现Android(RK平台)并没有直接提供直接的API用于获取RAM标称容量,怎么办呢?
想到一个折衷的办法,如上面所说,1GB内存标称的设备,实际容量有700MB左右。那么,对获取到的实际容量进行向上取整处理,便可以得到盒子的标称内存。至于向上取整可以使用Math类提供的ceil函数实现,如下方式获取。(没有办法的办法)
/**
* 获取运行内存标称容量(GB)
*
*/
public static String getMemNominalSize() {
String size= String.format("%.2f",Math.ceil(getMemTotalSize()/1024/1024));
Log.i(TAG, "get memory size: " + size + "GB");
return size;
}
目前设备使用的是这种向上取整的方式来获取RAM标称容量,也没什么问题。不过,Android没有提供获取RAM标称容量的接口,始终感觉缺点什么。而且,心里总感觉通过这样的方式来获取参数有点“委婉”。
后来有留意到,DDR (可以理解为内存的一种型号,在这里可以当成RAM来对待)相关的内核日志中,其实是有打印运行内存标称容量的!如截图中的关键字:Total Capability
看了一下内核代码,这个只是在内核中打印出了相关的参数信息,并没有向顶层提供接口。
因此,如果有必要的话,也是可以通过在内核层自己增加查询接口(比如 sys 或 proc),提供给顶层应用调用。
一般说到RAM,都会说到ROM,这两个像是一对欢喜冤家,谁也离不开谁,总会成对出现。在嵌入式尤其智能手机领域,RAM一般说的就是运行内存,而对于ROM,则有几个常见的说法。
首先,在智能手机,尤其 Android 设备盛行的今天,常常会听到给手机“刷机”,给手机“刷了一个新ROM”, “手机刷成板砖”这样的说法。这里的ROM指的是刷机所使用系统固件(只读内存镜像),常用于手机定制系统玩家的圈子中。常见的 ROM image 有 img、zip 等格式,前者通常用fastboot程序等刷机工具通过数据线刷入(线刷),后者通常用 recovery 模式从 sd刷入(卡刷),
因此 img 镜像也被称为线刷包,zip 镜像也被称为卡刷包。
拿RK3188来说,量产刷机所用的ROM镜像一般包含 system.img、boot.img、kernel.img、misc.img和recovery.img。以上镜像也可以打包为统一固件(update.img)。
在智能手机领域,ROM还指手机智能操作系统。很多定制系统玩家也会统一将定制过操作系统称为 ROM。 像比较有名的 小米的 MIUI, 锤子的 Smartisan OS,魅族的 Flyme, CM团队的 CyanogenMod…可谓是百家齐放,各有各家的奇葩特色。
而从根本上来讲,ROM其实只是只读存储器(Read-Only Memory)的简称,是一种只能读出事先所存数据的固态半导体存储器。 前面我们说到的ROM刷机镜像,ROM操作系统,说到底都是“存储”在这种存储介质上的,并且持有持久性,断电不丢失的特性。
对于我的开发板来说,采用Nandflash作为我们的ROM存储介质。按照百度百科的介绍,Nandflash内存是flash内存的一种,具有容量较大,改写速度快等优点,适用于大量数据的存储,因而在业界得到了越来越广泛的应用,如嵌入式产品中包括数码相机、MP3随身听记忆卡、体积小巧的U盘等。
同样地,Android提供了获取内部存储容量,内部和外部SDCard存储空间容量的API接口,却也没有给顶层应用开发直接提供获取Nandflash(ROM)存储总容量的接口。
既然没有直接提供,那就想办法吧。只要肯想,办法总是有的。Nandflash说到底只是一种flash内存器件,对于Android设备来说,不管是4GB还是8GB的flash容量,Android系统最后都是通过对这块Nandflash进行划分利用,即所谓的分区。分区之后,Android各个分区才能各司其职,保证系统正常运行。那么,对于一块Nandflash,Android是怎样进行划分的呢?各个分区又各自占用了多少容量呢?
下面简单介绍一下Nandflash存储容量的一些相关获取和计算方式。
Android下面,查看各分区容量(实际容量),有好几种方法,下面列出常用的两种,即通过linux sys文件系统和proc文件系统查看分区信息。
首先使用以下命令查看block块设备有哪些
ls /sys/class/block/
可以发现block目录下有一系列类似的目录,实际上,该目录下的所有子目录代表着系统中当前被发现的所有块设备,其中,mtdbolck0 - mtdblock9 这十个目录,便是设备系统对Nandflash进行分区所形成的block块设备:
随便进一个目录看看,看看有什么东西,比如 mtdblock0, 可以发现mtdblock0下面还有好多节点或子目录。
其中有一个size节点,我们想知道的分区容量,便可以通过此节点获取。cat命令查看size大小:
可以知道 mtdblock0 的 size为8192个单位 ,需要注意一下的是,这里的显示单位是records,1records = 512byte,也就是说,mtdblock0的容量大小为:
8192 records = 8192 * 512 byte = 4 * 1024 * 1024 byte = 4 Mb
类似地,其他几个mtdblock分区的大小,也可以通过以上的方式进行计算,而各个分区容量之和,便是这块Nand-flash的存储容量。
注意,这里计算出来的,是Nandflash的 实际容量,而非标称容量。至于Nandflash的标称容量的计算,下面会介绍。
获取各分区容量信息,还可以通过proc文件系统进行查看。我们知道,linux下面,通过 cat /proc/partitions 可以文件地知道系统本身的分区情况。同样地,Android也可以通过这样的方式查看分区信息。
同样可以清楚地看出有mtdblock0 - mtdblock9 10个分区,不仅如此,各个分区的容量信息也非常直观地显示了出来,如上图红色圈出来的部分。同样需要注意的是,这里的显示单位是blocks,1blocks = 1KB。还是拿mtdblock0进行计算:
4096 blocks = 4096 KB = 4 *1024 KB = 4 MB
计算结果与上面 sys文件系统计算出来是一样的!
将10个分区的容量之和相加,便可以得到Nandflash的存储容量(实际容量)。比如shell下面,通过以下方式,便可以很快计算其容量和:
cat /proc/partitions | awk 'BEGIN{sum=0} {sum+=$3} END{print sum}'
也就是说,Nandflash的实际存储容量为:3768320 KB = 3680 MB = 3.59375 GB
3768320 KB = 3680 MB = 3.59375 GB
将以上两个步骤统一起来,统一为一条命令来计算Nandflash容量(单位:GB):
cat /proc/partitions|awk 'BEGIN{sum=0} {if(NR>=3) {sum+=$3} } END{print expr sum/1024/1024}'
通过以上两种方式,便可以获取到Nandflash存储容量(实际容量)。
前面说的Nandflash容量指的都是实际容量。那么,怎么获取Nandflash的标称容量呢,即4GB 或 8GB这样的参数?还是同样的,Android没有提供直接的API接口供顶层调用。另外,通过以上介绍可以知道,通过分区信息也只能获取到Nandflash的实际容量,难道还要像运行内存那样,对获取到的Nandflash实际容量进行向上取整,进而获得标称容量?
当然,使用向上取整的方式也是可以计算Nandflash标称容量的. Nandflash标称容量为4GB的设备,实际容量为3.59375 GB左右,取上取整能得到准确的 4GB。8GB的设备,实际容量为7.2GB左右,向上取整也能得到8GB标称容量。
但是,不排除某些异常情况下,比如flash内存颗粒出现问题(Nandflash驱动会自动跳过坏块),这样有可能导致8 GB的Nandflash计算出来的实际容量只有6.999GB的话,这样向上取整只能得到7 GB。因此,使用这样的方式计算Nandflash标称容量在某些极端情况下是存在计算误差的!
那么,除了向上取整,别无他法了么?答案肯定是否定的,只要肯想,办法总是有的!
前面我们一直在说Nandflash,却忽略了一点,Nandflash 并不是一开始焊接到板子上面就可以正常使用的,这是需要内核Nandflash驱动支持的。那么,Nandflash驱动会不会给我们留下一些信息呢?
通过查阅内核Rockchip Nandflash驱动源码,发现一个惊喜,感觉里面会有我们想要的猫腻!如代码显示的,Nand-flash驱动会在系统起来后,创建/proc/rknand文件系统.
继续跟踪 rkNand_proc_read 函数:
其中,rknand_base_version 应该是驱动版本号,是一个固定的值:
本来还想继续跟踪 proc_ftlread和proc_bufread 源码,发现Rockchip并没有开源这部分代码,而是以ko闭源库的形式提供给我们使用。(我们设备内核版本是3.0.36+,对应的Nand-flash驱动为:rk30xxnand_ko.ko.3.0.36+)
既然Rockchip没有开源Nand-flash源码,那我们只好单刀直入,直接查看系统起来后 /proc/rknand节点信息了:
可以看到,/proc/rknand节点为我们提供了很多很多 Nand-flash 方面的具体信息:
比如前面说的rknand_base_version的版本号: rknand_base.c version: 4.40 20130420
比如 Flash ID: 9194d7ad
不过这些都与我们无关,我们关注的是,Nand-flash驱动有没有为我们提供存储容量方面的信息.你注意到了么,上图中圈中的Device Capacity,这个就是设备的Flash容量,而且是标称容量!
我们可以很直观地知道,这块Nandflash的标称容量是4096 MB,也就是4 GB!
知道了这一点,获取Nand-flash标称容量便轻而易举了:
cat /proc/rknand | grep "Device Capacity" | awk '{print $3}' (单位:MB)
Java编程环境下,可以使用以下方式获取:
/**
* 获取设备Flash存储容量
*
* @author lzr
*/
public String getDeviceCapacity(Context context) {
String capacity = DEFAULT_DEVICE_CAPACITY_IN_MB;
FileReader fileReader = null;
BufferedReader bufferedReader = null;
File file = new File(RKNAND_PATH);
if(file.exists()) {
try {
fileReader = new FileReader(RKNAND_PATH);
bufferedReader = new BufferedReader(fileReader, DEFAULT_FILE_SIZE);
String line = null;
while ((line = bufferedReader.readLine()) != null) {
if(line.indexOf("Device Capacity:") != -1) {
capacity = line.substring(line.indexOf("Device Capacity:")).replaceAll("\\D+", "");
Log.i(TAG, "get device capacity: " + capacity + " MB");
break;
}
}
}catch (IOException e) {
Log.w(TAG, "couldn't get device capacity in " + RKNAND_PATH + ",storage capacity defaults to 4GB.");
capacity=DEFAULT_DEVICE_CAPACITY_IN_MB;
}finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
}
}
}
}else {
Log.w(TAG, RKNAND_PATH + " not exist, storage capacity defaults to 4GB.");
capacity=DEFAULT_DEVICE_CAPACITY_IN_MB;
}
return formatSize(context,Long.valueOf(capacity) * 1024 * 1024L);
}
通过以上方式,对于RAM与ROM容量,就可以正确计算其标称容量和实际容量了!
以上对RAM及ROM的介绍,适用于Rockchip平台。对于其他非RK平台,可能计算方式稍微不一致,需要做适当的调整和修改。
通俗一点来理解RAM和ROM,就是Android中的RAM和ROM分别对应电脑的内存和硬盘,内存负责程序的运行以及数据交换,有了它,电脑中的软件才能运行,并有了进程;而硬盘就是一块存储空间,您可以存储各种各样的文件,包括视频、照片、音乐、软件等。
在Android设备中,RAM决定了Android设备可以同时运行多少应用程序以及运行速度;而ROM决定了Android设备的存储空间大小。ROM包含了安卓系统、软件、用户文件(照片、视频等)。而用户存储的文件只占据ROM空间,是不影响RAM空间的。其次,ROM空间的大小对系统运行速度的影响是微乎其微的;影响Android设备运行速度的最主要因素是RAM。