Java虚拟机内存区域的那点事

一、Java运行时数据区的组成

Java的运行时数据区分为两个区域,一个是线程私有的区域,一个是线程共享的区域。

  • 线程私有
    • Java虚拟机栈
    • 本地方法栈
    • 程序计数器
  • 线程共享
    • 方法区

Java虚拟机运行时数据区

二、Java运行时数据区分析

从上面已经知道了,Java虚拟机运行时数据区按照线程私有与否可以进行划分,线程私有的会随着线程的创建以及销毁,因此这是不需要进行垃圾回收的区域。而线程共享的会进行垃圾回收。

  • 程序计数器

    在Java中,假如单核CPU,同时有多条线程跑的情况下,线程之间可能在让出CPU执行权的时候,某条线程的还没执行完被切出去了,那么需要有一个记录此时线程执行的属性的,而完成这一使命的就是程序计数器。

    程序计数器用于记录线程执行的字节码的行数,线程的分支跳转、循环、条件控制都基于程序计数器而完成的。

    如果线程执行的是Java方法,程序计数器记录的是执行的字节码的指令地址。而如果执行的是Native方法,则这个计数器为空。

  • Java虚拟机栈

    Java虚拟机栈是线程私有的,每个线程都有一个栈,线程执行方法的过程对应的是栈帧的进栈以及出栈的过程。所以可以知道,栈帧实际上记录的就是方法的信息,比如局部变量表,动态链接,方法出口等信息。局部变量表存放的是基本数据类型以及对象引用。

    如果请求栈的深度超过允许的栈深度,则会抛出StackOverFlowError的异常。

  • 本地方法栈

    本地方法栈跟虚拟机栈是对应的,如果执行的不是Java的方法,那么就是在本地方法栈进行操作,同样会抛出StackOverFlowError的异常。

  • Java堆

    Java堆是在虚拟机启动的时候创建并划分大小的,Java堆的大小是可以通过参数进行控制的,设置Xmx跟Xms参数,空闲程度大于70%就调整到小的,小于40%就调整到大的,因为如此设置的话课比较频繁,所以很多case下都是设置为一样大小。

    Java堆主要存放的是对象以及数组。

  • 方法区

    方法区同样是线程共享的,分为两部分。方法区主要存放的是类信息,而里面还有一个运行时常量池,用于存放编译产生的字面量以及符号引用。

三、如何创建对象

Java作为一门面向对象语言,每时每刻都在产生对象。在语言层面,用到的是一个new关键字,但是在背后存在着复杂的逻辑。

  • Java虚拟机遇到一个new操作的时候,会先去常量池里面查看能否定位到一个符号引用,并检查该符号引用对应的类是否被加载、解析以及初始化过,如果没有则执行类加载的过程。

  • 创建对象的方式
    在不同的虚拟机上有不同创建对象的方式,主要有以下两种。

    • 指针碰撞

      假设在内存都是规整的前提下,内存分为两块,一块是已经使用的区域,一块是待分配的区域。指针位于两个区域的中间,当需要分配内存的时候,计算需要分配的对象的大小,然后进行划分一个区域空间进行分配即可。

    • 内存记录

      但是实际情况总是不是那么美好的,内存不可能一直都是工整的,在这个时候就需要有一个列表,记录着内存中哪一块是空闲的区域,当需要分配的时候,在内存列表上进行查找,分配一个足够大的内存进行分配。

坚持原创技术分享,您的支持将鼓励我继续创作!