【Android】Android内存机制,了解Android堆和栈

一、dalvik的Heap和Stack

这里说的只是dalvik java部分的内存,实际上除了dalvik部分,还有native。java

     下面针对上面列出的数据类型进行说明,只有了解了咱们申请的数据在哪里,才能更好掌控咱们本身的程序。

 二、对象实例数据

其实是保存对象实例的属性,属性的类型和对象自己的类型标记等,可是不保存实例的方法。实例的方法是属于数据指令,是保存在Stack里面,也就是上面表格里面的类方法。android

对象实例在Heap中分配好之后,会在stack中保存一个4字节的Heap内存地址,用来查找对象的实例。由于在Stack里面会用到Heap的实例,特别是调用实例的时候须要传入一个this指针。程序员

三、方法内部变量

  类方法的内部变量分为两种状况:简单类型保存在Stack中;对象类型在Stack中保存地址,在Heap 中保存值。shell

四、非静态方法和静态方法

  非静态方法有一个隐含的传入参数,这个参数是dalvik虚拟机传进去的,这个隐含参数就是对象实例在Stack中的地址指针。所以非静态方法(在Stack中的指令代码)老是能够找到本身的专用数据(在Heap 中的对象属性值)。缓存

  固然非静态方法也必须得到该隐含参数,所以非静态方法在调用前,必须先new一个对象实例,得到Stack中的地址指针,不然dalvik虚拟机将没法将隐含参数传给非静态方法。安全

  静态方法没有隐含参数,所以也不须要new对象,只要class文件被ClassLoader load进入JVM的Stack,该静态方法便可被调用。因此咱们能够直接使用类名调用类的方法。固然此时静态方法是存取不到Heap 中的对象属性的。ide

五、静态属性和动态属性

  静态属性是保存在Stack中的,而不一样于动态属性保存在Heap 中。正由于都是在Stack中,而Stack中指令和数据都是定长的,所以很容易算出偏移量,因此类方法(静态和非静态)均可以访问到类的静态属性。也正由于静态属性被保存在Stack中,因此具备了全局属性。this

六、小结

  Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象经过new、newarray、anewarray和multianewarray等指令创建,它们不须要程序代码来显式的释放。spa

  堆是由垃圾回收来负责的,堆的优点是能够动态地分配内存大小,生存期也没必要事先告诉编译器,由于它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些再也不使用的数据。但缺点是,因为要在运行时动态分配内存,存取速度较慢。线程

  栈的优点是,存取速度比堆要快,仅次于寄存器,栈数据能够共享。但缺点是,存在栈中的数据大小与生存期必须是肯定的,缺少灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。

  对比上面的解析能够看出,其实Java处理Heap和Stack的大体原理跟C++是同样的。只是多了一个内存回收机制,让程序员不用主动调用delete释放内存。就像在C++里面,通常使用new申请的内存才会放到堆里面,而通常的临时变量都是放到栈里面去。


七、APP默认分配内存大小

  在Android里,程序内存被分为2部分:native和dalvik,dalvik就是咱们普通的java使用内存,也就是刚分析堆栈的时候使用的内存。

  咱们建立的对象是在这里面分配的,对于内存的限制是 native+dalvik 不能超过最大限制。

  android程序内存通常限制在16M,也有的是24M(早期的Android系统G1,就是只有16M)。具体看定制系统的设置,在Linux初始化代码里面Init.c,能够查到到默认的内存大小。有兴趣的朋友,能够分析一下虚拟机启动相关代码。

  1. gDvm.heapSizeStart =2*1024*1024;// heap初始化大小为2M
    gDvm.heapSizeMax =16*1024*1024;// 最大的heap为16M

八、Android的GC如何回收内存

  Android的一个应用程序的内存泄露对别的应用程序影响不大。为了可以使得Android应用程序安全且快速的运行,Android的每一个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每一个应用程序都是在属于本身的进程中运行的。

  Android为不一样类型的进程分配了不一样的内存使用上限,若是程序在运行过程当中出现了内存泄漏的而形成应用进程使用的内存超过了这个上限,则会被系统视为内存泄漏,从而被kill掉,这使得仅仅本身的进程被kill掉,而不会影响其余进程(若是是system_process等系统进程出问题的话,则会引发系统重启)。

  作应用开发的时候,你须要了解系统的GC(垃圾回收)机制是如何运行的,Android里面使用有向图做为遍历回收内存的机制。

  Java将引用关系考虑为图的有向边,有向边从引用者指向引用对象。线程对象能够做为有向图的起始顶点,就是从起始顶点开始的一棵树,根顶点能够到达的对象都是有效对象,GC不会回收这些对象。若是某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么咱们认为这个(这些)对象再也不被引用,能够被GC回收。

  所以对于咱们已经不须要使用的对象,咱们能够把它设置为null,这样当GC运行的时候,就好遍历到你这个对象已经没有引用,会自动把该对象占用的内存回收。咱们无法像C++那样立刻释放不须要的内存,可是咱们能够主动告诉系统,哪些内存能够回收了。

九、查看应用内存使用状况

  下面咱们看看如何在开发过程当中查看咱们程序运行时内存使用状况。咱们能够经过ADB的一个命令查看:

  1. //$package_name:应用包名
    //$pid:应用进程ID,能够用PS命令查看
    adb shell dumpsys meminfo $package_name or $pid
  
  上面是我使用包名查看的内存使用状况图,里面信息不少,不过咱们主要关注的是native和Davilk的使用状况。
  Android底层内核是基于Linux的,而Linux里面相对Window来讲,有一点很特别的是,会尽可能使用系统内存加载一些缓存数据或者进程间共享数据。
  Linux本着不用白不用的原则,会尽可能使用系统内存,加快咱们应用的运行速度。固然,若是咱们期待某个须要大内存的应用,系统也能立刻释放出必定的内存使用,这是系统内部调度实现。所以严格来讲,咱们要准备计算Linux下某个进程内存大小比较困难。 由于有paging out to disk(换页),因此若是你把全部映射到进程的内存相加,它可能大于你的内存的实际物理大小。
  • dalvik:是指dalvik所使用的内存。
  • native:是被native堆使用的内存。应该指使用C\C++在堆上分配的内存。
  • other:是指除dalvik和native使用的内存。可是具体是指什么呢?至少包括在C\C++分配的非堆内存,好比分配在栈上的内存。puzlle!
  • Pss:它是把共享内存根据必定比例分摊到共享它的各个进程来计算所获得进程使用内存。网上又说是比例分配共享库占用的内存,也就是上面所说的进程共享问题。
  • PrivateDirty:它是指非共享的,又不能换页出去(can not be paged to disk )的内存的大小。好比Linux为了提升分配内存速度而缓冲的小对象,即便你的进程结束,该内存也不会释放掉,它只是又从新回到缓冲中而已。
  • SharedDirty:参照PrivateDirty我认为它应该是指共享的,又不能换页出去(can not be paged to disk )的内存的大小。好比Linux为了提升分配内存速度而缓冲的小对象,即便全部共享它的进程结束,该内存也不会释放掉,它只是又从新回到缓冲中而已。

十、程序中获取内存信息

经过ActivityManager获取相关信息,下面是一个例子代码:

  1. 1 privatevoid displayBriefMemory()
    2 {
    3     finalActivityManager activityManager =(ActivityManager) getSystemService(ACTIVITY_SERVICE);
    4     ActivityManager.MemoryInfo info =newActivityManager.MemoryInfo();
    5     activityManager.getMemoryInfo(info);
    6     Log.i(tag,"系统剩余内存:"+(info.availMem >>10)+"k");
    7     Log.i(tag,"系统是否处于低内存运行:"+info.lowMemory);
    8     Log.i(tag,"当系统剩余内存低于"+info.threshold+"时就当作低内存运行");
    9 }
    View Code
  另外经过Debug的getMemoryInfo(Debug.MemoryInfo memoryInfo)能够获得更加详细的信息。跟咱们在ADB Shell看到的信息同样比较详细。

十一、小结

  以上主要是分析了如何获取咱们应用的内存使用状况信息,关于这方面的信息,其实还有其余一些方法。

  上面只是很浅薄地分析了一下,有个印象。这些东西真要深刻分析得花很多精力。

相关文章
相关标签/搜索