JVM基础知识

       JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是经过在实际的计算机上仿真模拟各类计算机功能来实现的。html

JVM内存组成结构java

一、本地方法栈算法

用于支持native方法的执行,存储了每一个native方法调用的状态jvm

二、方法区性能

存放了要加载的类信息、静态变量、final类型的常量、属性和方法信息。JVM用持久代(Permanet Generation)来存放方法区,可经过-XX:PermSize和-XX:MaxPermSize来指定最小值和最大值测试

三、JAVA栈spa

       在jvm中栈用来存储一些对象的引用(例如方法引用)、基本数据类型(boolean、byte、char、short、int、float、long、double)。它的存储比堆快得多,只比CPU里的寄存器慢。每一个线程都有本身的Stack Space(栈),在JDK5.0以前每一个线程栈大小为256k,JDK5.0以后改成1M。线程

*使用递归时若是深度过深很容易致使栈溢出(StackOverflowError),此时能够经过设置栈大小来处理(-Xss:如-Xss128k)htm

测试用例:对象

public class StackTest{

    private static int count=0;

    public static void add(long a,long b){
        count++;
        add(a,b);
    }
    public static void main(String args[]){
        try{
            add(0L,0L);
        }catch(Throwable e){
            System.out.println("深度为: "+count);
            System.exit(0);
            e.printStackTrace();
        }
    }
}

-Xss分别设置成128k和256k结果分别为:

深度为: 8964(128k)

深度为: 17700 (256K)

四、JAVA堆

一:新生代:主要是用来存放新生的对象。通常占据堆的1/3空间。因为频繁建立对象,因此新生代会频繁触发MinorGC进行垃圾回收。

         新生代又分为 Eden区、ServivorFrom、ServivorTo三个区。

         Eden区:Java新对象的出生地(若是新建立的对象占用内存很大,则直接分配到老年代)。当Eden区内存不够的时候就会触发MinorGC,对新生代区进行一次垃圾回收。

         ServivorTo:保留了一次MinorGC过程当中的幸存者。

         ServivorFrom:上一次GC的幸存者,做为这一次GC的被扫描者。

         MinorGC的过程:MinorGC采用复制算法。首先,把Eden和ServivorFrom区域中存活的对象复制到ServicorTo区域(若是有对象的年龄以及达到了老年的标准,则赋值到老年代区),同时把这些对象的年龄+1(若是ServicorTo不够位置了就放到老年区);而后,清空Eden和ServicorFrom中的对象;最后,ServicorTo和ServicorFrom互换,原ServicorTo成为下一次GC时的ServicorFrom区。

 

二:老年代:主要存放应用程序中生命周期长的内存对象。

    老年代的对象比较稳定,因此MajorGC不会频繁执行。在进行MajorGC前通常都先进行了一次MinorGC,使得有新生代的对象晋身入老年代,致使空间不够用时才触发。当没法找到足够大的连续空间分配给新建立的较大对象时也会提早触发一次MajorGC进行垃圾回收腾出空间。

    MajorGC采用标记—清除算法:首先扫描一次全部老年代,标记出存活的对象,而后回收没有标记的对象。MajorGC的耗时比较长,由于要扫描再回收。MajorGC会产生内存碎片,为了减小内存损耗,咱们通常须要进行合并或者标记出来方便下次直接分配。

     当老年代也满了装不下的时候,就会抛出OOM(Out of Memory)异常。

 

 三:永久代

    指内存的永久保存区域,主要存放Class和Meta(元数据)的信息,Class在被加载的时候被放入永久区域. 它和和存放实例的区域不一样,GC不会在主程序运行期对永久区域进行清理。因此这也致使了永久代的区域会随着加载的Class的增多而胀满,最终抛出OOM异常。

    在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。

    元空间的本质和永久代相似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。所以,默认状况下,元空间的大小仅受本地内存限制。类的元数据放入 native memory, 字符串池和类的静态变量放入java堆中. 这样能够加载多少类的元数据就再也不由MaxPermSize控制, 而由系统的实际可用空间来控制.

    采用元空间而不用永久代的几点缘由:(参考:http://www.cnblogs.com/paddix/p/5309550.html)

  一、为了解决永久代的OOM问题,元数据和class对象存在永久代中,容易出现性能问题和内存溢出。

  二、类及方法的信息等比较难肯定其大小,所以对于永久代的大小指定比较困难,过小容易出现永久代溢出,太大则容易致使老年代溢出(由于堆空间有限,此消彼长)。

  三、永久代会为 GC 带来没必要要的复杂度,而且回收效率偏低。

*堆内存设置

-Xmx:最大堆内存,如:-Xmx512m  (默认是物理内存的1/4)

-Xms:初始时堆内存,如:-Xms256m  (默认是物理内存的1/64)

-XX:MaxNewSize:最大年轻区内存

-XX:NewSize:初始时年轻区内存.一般为 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 个 Survivor 空间。实际可用空间为 = Eden + 1 个 Survivor,即 90%

-XX:MaxPermSize:最大持久带内存

-XX:PermSize:初始时持久带内存

-XX:+PrintGCDetails。打印 GC 信息

 -XX:NewRatio 新生代与老年代的比例,如 –XX:NewRatio=2,则新生代占整个堆空间的1/3,老年代占2/3

 -XX:SurvivorRatio 新生代中 Eden 与 Survivor 的比值。默认值为 8。即 Eden 占新生代空间的 8/10,另外两个 Survivor 各占 1/10

 

JVM GC触发

1.Minor GC

从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC(好比当 Eden 区满了)

2.Major GC 

是清理老年代(通常老年代空间不足时触发)。

3.Full GC 

是清理整个堆空间—包括年轻代和老年代

Full GC触发条件:

(1)调用System.gc时,系统建议执行Full GC,可是没必要然执行

(2)老年代空间不足

(3)方法区空间不足

(4)经过Minor GC后进入老年代的平均大小大于老年代的可用内存

(5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小  

相关文章
相关标签/搜索