每一个线程都拥有本身的栈,当前执行的方法在栈的顶部,每次方法调用时,一个新的栈帧建立并压到栈顶。当方法正常返回或抛出未捕获的异常时,栈帧就会出站。java
栈能够是动态分配也能够固定大小。若是线程请求一个超过容许范围的空间,就会抛出一个StackOverflowError。若是线程须要一个新的栈帧,可是没有足够的内存能够分配,就会抛出一个 OutOfMemoryError。算法
/** * @author LXA * 栈溢出 */ public class Stack { public static void main(String[] args) { new Stack().test(); } public void test() { test(); } }
报错:缓存
java.lang.StackOverflowError
当前调用的方法会在栈中建立栈帧,方法陷入死循环中,就会不停的在栈中建立对象,而不会销毁栈帧,直到栈没有空间时,就会溢出。函数
类被初始化是,new出的对象,被分配在堆上,对象不停的建立,并且不被释放,在垃圾回收机制中,占满青年代,将会被移到老年代中,当老年代中的空间不够时,就会oom。spa
/** * @author LXA * 堆溢出 */ public class Heap { public static void main(String[] args) { ArrayList list=new ArrayList(); while(true) { list.add(new Heap()); } } }
报错:线程
报错: java.lang.OutOfMemoryError: Java heap space
基于 标记清除算法进行的。 新生代收集器使用的收集器:Serial、PraNew、Parallel Scavenge 老年代收集器使用的收集器:Serial Old、Parallel Old、CMS指针
4、GC的执行机制code
因为对象进行了分代处理,所以垃圾回收区域、时间也不同。GC有两种类型:Scavenge GC和Full GC。对象
Scavenge GC接口
通常状况下,当新对象生成,而且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,而且把尚且存活的对象移动到Survivor区。而后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。由于大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,因此Eden区的GC会频繁进行。于是,通常在这里须要使用速度快、效率高的算法,使Eden去能尽快空闲出来。
Full GC
对整个堆进行整理,包括Young、Tenured和Perm。Full GC由于须要对整个堆进行回收,因此比Scavenge GC要慢,所以应该尽量减小Full GC的次数。在对JVM调优的过程当中,很大一部分工做就是对于FullGC的调节。有以下缘由可能致使Full GC:
1.年老代(Tenured)被写满
2.持久代(Perm)被写满
3.System.gc()被显示调用
4.上一次GC以后Heap的各域分配策略动态变化
通常来讲内存泄漏有两种状况。一种状况如在C/C++ 语言中的,在堆中的分配的内存,在没有将其释放掉的时候,就将全部能访问这块内存的方式都删掉(如指针从新赋值);另外一种状况则是在内存对象明明已经不须要的时候,还仍然保留着这块内存和它的访问方式(引用)。第一种状况,在 Java 中已经因为垃圾回收机制的引入,获得了很好的解决。因此, Java 中的内存泄漏,主要指的是第二种状况。
Vector v = new Vector( 10 ); for ( int i = 1 ;i < 100 ; i ++ ){ Object o = new Object(); v.add(o); o = null ; }
在这个例子中,代码栈中存在Vector 对象的引用 v 和 Object 对象的引用 o 。在 For 循环中,咱们不断的生成新的对象,而后将其添加到 Vector 对象中,以后将 o 引用置空。问题是当 o 引用被置空后,若是发生 GC ,咱们建立的 Object 对象是否可以被 GC 回收呢?答案是否认的。由于, GC 在跟踪代码栈中的引用时,会发现 v 引用,而继续往下跟踪,就会发现 v 引用指向的内存空间中又存在指向 Object 对象的引用。也就是说尽管 o 引用已经被置空,可是 Object 对象仍然存在其余的引用,是能够被访问到的,因此 GC 没法将其释放掉。若是在此循环以后, Object 对象对程序已经没有任何做用,那么咱们就认为此 Java 程序发生了内存泄漏。
用于存放静态文件,现在Java类、方法等。持久代对垃圾回收没有显著影响,可是有些应 用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候须要设置一个比较大的持 久代空间来存放这些运行过程当中新增的类。持久代大小经过-XX:MaxPermSize=<N>进行设置。
持久带补充:持久带也称为方法区 方法区:方法区存储每个java类的结构信息:好比运行时常量池,字段和方法数据,构造函数和普通方法的字节码内容以及类、实例、接口初始化时须要使用到的特殊方法等数据。 方法区也被称为永久代,若是不显示指定的话,GC回收的目标仅针对方法区的常量池和类型卸载
非堆内存包括: 永久代,包括: 方法区 驻留字符串(interned strings) 代码缓存(Code Cache):用于编译和存储那些被 JIT 编译器编译成原生代码的方法。