Java内存区域

方法区:用于存放已被虚拟机加载的类信息、常量、静态变量、编译器编译后的代码等数据。
    运行时常量池:是方法区的一部分,用于存放编译器生成的各种字面量和符号引用。
    当方法区无法满足内存分配需求时,会抛出OutOfMemoryError异常。
    方法区是线程共享的。

:在虚拟机启动时创建,用于存放对象实例和数组元素。
    如果堆中没有内存完成实例分配,并且堆也无法扩展时,会抛出OutOfMemoryError异常。
    堆是线程共享的。

虚拟机栈:虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
    局部变量表:用于存放方法参数和方法内部定义的局部变量。
    操作数栈:用于存放方法执行过程中的变量数据,如整数加法的字节码指令iadd从栈顶取出两个int型元素,执行加操作,然后将相加的结果入栈。    
    动态链接:Class文件的常量池中存有大量的符号引用,字节码中方法调用指令就以常量池中指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或第一次使用的时候就转化为直接引用,这种转化称为静态解析。另外一部分在每一次运行期间转化为直接引用,这部分称为动态链接。
    方法出口:一个方法开始执行后,只有两种方式可以退出这个方法:一种是执行引擎遇到方法返回的字节码指令,这种退出方式称为正常完成出口;另一种是方法执行过程中遇到了异常,且这个异常没有在方法体内得到处理,就会导致方法退出,这种退出方式称为异常完成出口。一个方法使用异常完成出口的方式退出,是不回给它的上层调用者产生任何返回值的。
    线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展,但是扩展时无法申请到足够内存,会抛出OutOfMemoryError异常。
    虚拟机栈是线程私有的。

本地方法栈:本地方法栈与虚拟机栈功能类似,只是本地方法栈服务于native方法。
    本地方法栈同样会抛出StackOverflowError异常和OutOfMemoryError异常。
    本地方法栈是线程私有的。

程序计数器:当前线程锁执行的字节码的行号指示器。如果线程正在执行的是一个Java方法,计数器记录的是正在执行的虚拟机季节吗指令的地址;如果正在执行的是native方法,计数器的值为空(Undefined)。此区域不会出现OutOfMemoryError。
    程序计数器是线程私有的。

对象的创建过程:虚拟机遇到一条new指令时,首先去检查这个指令的参数能否在常量池中定位到一个符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,必须先执行相应的类加载过程。接下来虚拟机将为新生对象分配内存,分配内存的方式有两种:”指针碰撞”(堆中内存是规整的,已分配和未分配的内存各属一边,一个指针记录着边界,每次指针向未分配的内存一边移动与对象大小相等的距离)和“空闲列表”(堆中内存不是规整的,即已分配和未分配的内存是相互交错的,虚拟机需要维护一个表,记录哪些空间是可用的,分配内存的时候从表中找到一块合适的空间分配给实例),采用哪种方式取决于堆是否规整,而堆是否规整取决于垃圾收集器是否具有压缩整理功能。 接下来虚拟机对对象进行必要的设置,如对象的哈希码、GC分代年龄等信息,这些信息存放于对象头中。至此,从虚拟机的视角,一个新的对象已经产生了,但从Java程序视角,对象创建才刚刚开始,还需要执行<init>方法,初始化对象等操作。

posted on 2017-07-15 16:45  LG一直在努力  阅读(178)  评论(0编辑  收藏  举报

导航