android内存管理

android内存管理

应用场景

我们在开发应用程序的时候,了解其内存的运作机制以及如何防止内存泄漏都是非常重要的,内存问题也是android面试中经常问到话题。今天我就讲讲有关android内存管理方面的知识吧。


android内存机制

首先,每个app都有最大的内存限制,而在android的内容管理上使用的是Dalvik虚拟机,该虚拟机的内存大体上可以分为Java Object Heap、Bitmap Memory和Native Heap三种。

Java Object Heap

Java Object Heap是用来分配java对象的,也就是我们在代码中new出来的对象都是位于Java Object Heap上的。我们可以通过AcivityManager来获取到系统为应用分配的内存空间:
 //获取最大内存资源
        ActivityManager activityManager= (ActivityManager) MainActivity.this.getSystemService(Context.ACTIVITY_SERVICE);
        int maxMemory= activityManager.getMemoryClass();
下面是源码:
/**
     * Return the approximate per-application memory class of the current
     * device.  This gives you an idea of how hard a memory limit you should
     * impose on your application to let the overall system work best.  The
     * returned value is in megabytes; the baseline Android memory class is
     * 16 (which happens to be the Java heap limit of those devices); some
     * device with more memory may return 24 or even higher numbers.
     */
    public int getMemoryClass() {
        return staticGetMemoryClass();
    }
源码的注释大体意思也就是为了整个系统的体验,虚拟机需要设定最大内存资源。Java Object Heap的最小和最大默认值为2M和16M,但是手机在出厂时,厂商会根据手机的配置情况来对其进行调整,例如,G1、Droid、Nexus One和Xoom的Java Object Heap的最大值分别为16M、24M、32M 和48M。

这个Java Object Heap的最大值也就是我们平时所说的Android应用程序进程能够使用的最大内存。这里必须要注意的是,Android应用程序进程能够使用的最大内存指的是能够用来分配Java Object的堆。

在Android3.0以及更高的版本中,我们还可以在AndroidManifest.xml的application标签中增加一个值等于“true”的android:largeHeap属性来通知Dalvik虚拟机应用程序需要使用较大的Java Object Heap。事实上这个属性受限于手机内存,同时也会影响系统体验(毕竟系统总共可用的内存是固定的,一个应用程序用得多了,就意味意其它应用程序用得少了)。

Bitmap Memory

Bitmap Memory也称为External Memory,它是用来处理图像的,这部分内存受Java Object Heap的大小限制的

在Android3.0之前,Bitmap Memory是在Native Heap中分配的,但是这部分内存同样计入Java Object Heap中,也就是说,Bitmap占用的内存和Java Object占用的内存加起来不能超过Java Object Heap的最大值。这就是为什么我们在调用BitmapFactory相关的接口来处理大图像时,会抛出一个OutOfMemoryError异常的原因。

在Android3.0以及更高的版本中,Bitmap Memory就直接是在Java Object Heap中分配了,这样就可以直接接受GC的管理。


Native Heap

Native Heap就是在Native Code中使用malloc等分配出来的内存,这部分内存是不受Java Object Heap的大小限制的,也就是它可以自由使用,当然它是会受到系统的限制。但是有一点需要注意的是,不要因为Native Heap可以自由使用就滥用,因为滥用Native Heap会导致系统可用内存急剧减少,从而引发系统采取激进的措施来Kill掉某些进程,用来补充可用内存,这样会影响系统体验。

在我们编写的C/C++申请的内存在Nativa Heap中

java内存分配策略

Java 程序运行时的内存分配策略有三种,分别是静态分配,栈式分配,和堆式分配,对应的,三种存储策略使用的内存空间主要分别是静态存储区(也称方法区)、栈区和堆区。

静态存储区(方法区):主要存放静态数据、全局 static 数据和常量。这块内存在程序编译时就已经分配好,并且在程序整个运行期间都存在。 

栈区 :当方法被执行时,方法体内的局部变量都在栈上创建,并在方法执行结束时这些局部变量所持有的内存将会自动被释放。因为栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 
堆区 : 又称动态内存分配,通常就是指在程序运行时直接 new 出来的内存。这部分内存在不使用时将会由 Java 垃圾回收器来负责回收。 
栈与堆的区别:

在方法体内定义的(局部变量)一些基本类型的变量和对象的引用变量都是在方法的栈内存中分配的。当在一段方法块中定义一个变量时,Java 就会在栈中为该变量分配内存空间,当超过该变量的作用域后,该变量也就无效了,分配给它的内存空间也将被释放掉,该内存空间可以被重新使用。

堆内存用来存放所有由 new 创建的对象(包括该对象其中的所有成员变量)和数组。在堆中分配的内存,将由 Java 垃圾回收器来自动管理。在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,这个特殊的变量就是我们上面说的引用变量。我们可以通过这个引用变量来访问堆中的对象或者数组。

举个例子
public class Sample() {

    int s1 = 0;
    Sample mSample1 = new Sample();
    public void method() {
        int s2 = 1;
        Sample mSample2 = new Sample();
    }
}
Sample mSample3 = new Sample();

Sample 类的局部变量 s2 和引用变量 mSample2 都是存在于栈中,但 mSample2 指向的对象是存在于堆上的。

mSample3 指向的对象实体存放在堆上,包括这个对象的所有成员变量 s1 和 mSample1,而它自己存在于栈中。

结论:

局部变量的基本数据类型和引用存储于栈中,引用的对象实体存储于堆中。—— 因为它们属于方法中的变量,生命周期随方法而结束。

成员变量全部存储与堆中(包括基本数据类型,引用和引用的对象实体)—— 因为它们属于类,类对象终究是要被new出来使用的。

android内存管理

Android虚拟机的垃圾回收采用的是根搜索 算法 。GC会从根节点(GC Roots)开始对heap进行遍历。到最后,部分没有直接或者间接引用到GC Roots的就是需要回收的垃圾,会被GC回收掉。而内存泄漏出现的原因就是存在了无效的引用,导致本来需要被GC的对象没有被回收掉。
通俗点讲也就是当没有任何可达性指向你的时候,你也就不应该有存活下去的理由了,这是GC就会理所应当的将你回收来释放内存。所以说我们要做的就是要写好代码,保证不用的不发生内存泄漏问题就可以了。

android内存泄漏的监控与调试

打开Android Studio,编译代码,在模拟器上运行,点击进入如下界面
选择相应的Tab
Memory一栏中,可以观察不同时间App内存的动态使用情况,点击黄色小车图案可以手动触发GC,点击黄色小车右边的图案进入到HPROF Viewer界面,查看Java的Heap,如下图:

Reference Tree代表指向该实例的引用,可以从这里面查看内存泄漏的原因,Shallow Size指的是该对象本身占用内存的大小,Retained Size代表该对象被释放后,垃圾回收器能回收的内存总和。
如何使用androidstudio来找到内存泄漏的对象呢?首先我们先启动一个应用。然后把玩一番,突然发现内存不断的增加如下图
这时我们手动进行GC然后再次点击查看java heap
点击上面的运行按钮就会帮助我们分析出发生内存泄漏的对象。

分析结果显示LoginActivity发生了内存泄漏情况我们在ReferenceTree中可以查看那些地方还持有它的实例,这样便于我们优化代码。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值