这里说的只是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申请的内存才会放到堆里面,而通常的临时变量都是放到栈里面去。
在Android里,程序内存被分为2部分:native和dalvik,dalvik就是咱们普通的java使用内存,也就是刚分析堆栈的时候使用的内存。
咱们建立的对象是在这里面分配的,对于内存的限制是 native+dalvik 不能超过最大限制。
android程序内存通常限制在16M,也有的是24M(早期的Android系统G1,就是只有16M)。具体看定制系统的设置,在Linux初始化代码里面Init.c,能够查到到默认的内存大小。有兴趣的朋友,能够分析一下虚拟机启动相关代码。
gDvm.heapSizeStart =2*1024*1024;// heap初始化大小为2M gDvm.heapSizeMax =16*1024*1024;// 最大的heap为16M
Android的一个应用程序的内存泄露对别的应用程序影响不大。为了可以使得Android应用程序安全且快速的运行,Android的每一个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每一个应用程序都是在属于本身的进程中运行的。
Android为不一样类型的进程分配了不一样的内存使用上限,若是程序在运行过程当中出现了内存泄漏的而形成应用进程使用的内存超过了这个上限,则会被系统视为内存泄漏,从而被kill掉,这使得仅仅本身的进程被kill掉,而不会影响其余进程(若是是system_process等系统进程出问题的话,则会引发系统重启)。
作应用开发的时候,你须要了解系统的GC(垃圾回收)机制是如何运行的,Android里面使用有向图做为遍历回收内存的机制。
Java将引用关系考虑为图的有向边,有向边从引用者指向引用对象。线程对象能够做为有向图的起始顶点,就是从起始顶点开始的一棵树,根顶点能够到达的对象都是有效对象,GC不会回收这些对象。若是某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么咱们认为这个(这些)对象再也不被引用,能够被GC回收。
所以对于咱们已经不须要使用的对象,咱们能够把它设置为null,这样当GC运行的时候,就好遍历到你这个对象已经没有引用,会自动把该对象占用的内存回收。咱们无法像C++那样立刻释放不须要的内存,可是咱们能够主动告诉系统,哪些内存能够回收了。
下面咱们看看如何在开发过程当中查看咱们程序运行时内存使用状况。咱们能够经过ADB的一个命令查看:
//$package_name:应用包名 //$pid:应用进程ID,能够用PS命令查看 adb shell dumpsys meminfo $package_name or $pid
经过ActivityManager获取相关信息,下面是一个例子代码:
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 }
以上主要是分析了如何获取咱们应用的内存使用状况信息,关于这方面的信息,其实还有其余一些方法。
上面只是很浅薄地分析了一下,有个印象。这些东西真要深刻分析得花很多精力。