从抽象的JVM的角度去看分为:堆(Heap),栈(Stacks),方法区(MethodArea),运行时常量池(RuntimeConstant Pool),本地方法栈(NativeMethod Stacks),PC Register(PC寄存器)。java
区别:堆是不连续的内存区域,堆空间比较灵活也特别大。 栈式一块连续的内存区域,大小是有操做系统觉决定的。堆管理很麻烦,频繁地new/remove会形成大量的内存碎片,这样就会慢慢致使效率低下。对于栈的话,他先进后出,进出彻底不会产生碎片,运行效率高且稳定。算法
咱们一般说的内存泄露,GC,是针对Heap内存的. 由于Stack内存在函数出栈的时候就销毁了。函数
public class A{ int a = 1; Student s1 = new Student();
public void Test(){ int b = 1; Student s2 = new Student(); } }
请问a的内存在哪里,b的内存在哪里,s1,s2的内存在哪里?记住下面两句话。大数据
因此答案就是a,s1, s2对象都在堆中,b和s2对象引用在栈中。spa
从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。操作系统
当一个对象已经不须要再使用了,本该被回收时,而有另一个正在使用的对象持有它的引用,从而就致使对象不能被回收。这种致使了本该被回收的对象不能被回收而停留在堆内存中,就产生了内存泄漏。线程
内存泄露的场景有不少。code
非静态内部类的静态实例
因为内部类默认持有外部类的引用,而静态实例属于类。因此,当外部类被销毁时,内部类仍然持有外部类的引用,导致外部类没法被GC回收。所以形成内存泄露。对象
类的静态变量持有大数据对象
静态变量长期维持到大数据对象的引用,阻止垃圾回收。blog
资源对象未关闭
资源性对象如Cursor、Stream、Socket,Bitmap,应该在使用后及时关闭。未在finally中关闭,会致使异常状况下资源对象未被释放的隐患。
注册对象未反注册
咱们经常写不少的Listener,未反注册会致使观察者列表里维持着对象的引用,阻止垃圾回收。
Handler经过发送Message与主线程交互,Message发出以后是存储在MessageQueue中的,有些Message也不是立刻就被处理的。
这个太多了,不细说,单利模式写的不恰当就属于这种。
根搜索算法是从离散数学中的图论引入的,程序把全部的引用关系看做一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点之后,继续寻找这个节点的引用节点,当全部的引用节点寻找完毕以后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。若是这个对象是引用可达的, 则称之为活的(live), 反之, 若是这个对象引用不可达, 则称之为死的(dead), 也能够称之为垃圾(garbage).这个引用可达与不可达就是相对于GC Root来讲的,在上图中,左边4个对象就是活的,右边两个就是死的,也就是咱们说的能够被回收的垃圾。