对于java 程序员来说,在虚拟机自动内存管理机智的帮助下,不需要为每一个new 操作去写配对的delete/free代码,不容易出现内存泄漏和内存溢出的问题,由虚拟机管理内存这一切看起来都很美好,不过正因为java程序员把内存控制的的权利java虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不清楚虚拟机是怎样使用内存的,那么排查错误将会是一项异常艰难的工作。(ps: java程序员和c程序员对内存的态度,就像钱钟书先生在《围城》中所说一样:城外的人想进去,城里的人想出来) 

    要了解jvm,首先必须先了解jvm的运行时数据区域  ;

       java虚拟机在执行java程序过程中会把它管理的内存划分个若干个不同的区域,这些区域有各自不同的用途,以及创建和销毁时间,有的区域(Merthod Area \Heap)随虚拟机进程启动而存在,有的区域(VM sTACK\Native Method Stack\Program Counter Register)则依赖用户线程的启动和结束而建立和销毁。

  

 程序计数器(Program Counter Resgister)

          是一块较小的内存空间,它可以看作是当前线程所执行字节码的行号指示器,字节码解释器工作时就是就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、跳转、异常处理、线程恢复等基础功能需要这个计数器来完成。

此区域是唯一一个在虚拟机规范中没有任何oom情况的区域·。

          如何理解: java虚拟机的多线程是通过线程的轮流切换并分配处理器的执行时间的方式来实现的,在任何一个确定的时刻,一个处理器都只会执行一条线程中的指令,因此,为了线程切换换后能恢复到正确的执行位置,每个线程都需要一个独立的程序计数器,各线程之间的计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

虚拟机栈(VM Stack)

         与程序计数器一样,虚拟机栈也是线程私有,它的生命周期与线程相同,该区域描述的是java方法执行的内存模型:每个方法在执行时都会创建一个栈帧(Stack Frame) 用于存储局部变量、操作数栈(https://www.cnblogs.com/chendongfly/p/4189707.htm)、动态链接(在后面类加载机制中会做说明)、方法出口信息(现在知道栈为啥是先进后出了吧)。每个方法从调用直到执行完成的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。

        这个区域规定了2种异常:

         StackOverfloeError:线程请求栈深度大于虚拟机所允许的深度。

         OOM:大部分虚拟机支持动态扩展,但扩展时无法申请到足够的内存,则会抛出该异常。

本地方法栈(Native Method Stack)

     与虚拟机栈基本一样,唯一不同是执行的本地方法(在java源码中)。

Java堆(Java Heap)

     java虚拟机中最大的一部分,各个线程共享区域,GC的主要区域,后面分析GC时在着重分析

方法区(Method Area)

   与java堆一样是各个线程共享区域,用于存储已被虚拟机加载的类的信息、常量、静态变量、即使编译器编译后的代码。虽然java虚拟机规范把方法区描述为堆的一个逻辑部分,但他却有一个名字叫Non-Heap(非堆),目的是与Java堆区分开来。

其他比较重要的区域还有:

    运行时常量池:是方法区的一部分

    直接内存:该区域在NIO中被广泛应用,主要用于提升效率。