JVM的内存区域的溢出

栈溢出

每一个线程都拥有本身的栈,当前执行的方法在栈的顶部,每次方法调用时,一个新的栈帧建立并压到栈顶。当方法正常返回或抛出未捕获的异常时,栈帧就会出站。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的各域分配策略动态变化

Java内存泄露

通常来讲内存泄漏有两种状况。一种状况如在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 编译器编译成原生代码的方法。

加载的类过多时,就会溢出

相关文章
相关标签/搜索