JVM的组成

JVM的组成

Java虚拟机在执行Java程序的过程中会把它管理的内存划分为不同的几个内存区域,每个区域对应不用的用途,创建和销毁的时间。有的区域是随着虚拟机进程的启动而启动,有的则是同用户的线程相关。如未特别指出,本文所讨论的是泛化的JVM,不是某一种特定的JVM实现。

根据《Java虚拟机规范》(后简称《规范》)的规定,JVM所管理的内存区域应当包含有:方法区、虚拟机栈、本地方法栈、堆和程序计数器。

程序计数器

程序计数器是一块较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。了解计算机组成原理的,可以类比一下PC的作用,尽管二者并不相同。程序计数器是归线程独有的,即每一个线程都需要一个自己的独立的程序计数器,原因涉及到线程的上下文切换

Java虚拟机的多线程是通过线程轮流切换+CPU调度的方式来实现的,在任何一个确定的时刻,每一个kernel只会执行一个线程(其实是线程中的一个指令,main方法也是一个线程,即主线程)。因此为了线程切换后能够正常的继续运行,每个线程有自己的程序计数器。

Java虚拟机栈

Java虚拟机栈也是线程私有的,生命周期同线程相同。其实这部分描述的是Java方法执行中的内存结构,每一个方法执行的时候会在虚拟机栈中创建一个栈帧指向局部变量表(编译时可知的基础类型、对象引用和returnAddress类型)、操作数栈、动态连接和方法出口等信息。方法的执行与返回的过程对应入栈和出栈的过程。

《规范》中对这部分描述了两类异常情况,一种就是常见的StackOverflowError,常发生与线程请求的栈深度大于虚拟机栈允许的深度。另一种是OutOfMemoryError异常,当虚拟机栈可以动态拓展且无法申请到足够的内存时会抛出此类异常。

本地方法栈

本地方法栈和Java虚拟机很相似,区别在于虚拟机栈为Java程序服务,本地方法栈为native方法服务。因此有的虚拟机如Hot-Spot将二者合并在了一起。

Java堆

Java堆同栈、程序计数器不同,Java堆是线程共享的。堆的作用就是存放对象,几乎所有的对象都会在堆上分配内存。但是目前,随着编译能力的提高,尤其是逃逸分析技术的发展,栈上分配和标量替换等优化已经并不少见了。例如如下代码中myObject属于局部变量,只能够在方法中被访问到,因此会直接在栈上分配内存,可以快速回收。

public void myMethod(){

    ...
    MyObject myObject = new MyObject();
    ...

}

虽然我们上面提到了堆是共享的,但是堆上也为每一个线程保留了一小块儿内存用于线程私有缓冲区,这些缓冲区被称作TLAB。在对象分配时,可以现在线程的缓冲区上分配,然后同步到堆中,该特性可以根据JVM参数-XX:+/UseTLAB控制。

当堆中无法分配实例对象内存且无法拓展时,会抛出OutOfMemoryError异常。

方法区

方法区一般用于存放虚拟机加载的类型信息、常量、静态变量和即时编译器编译后的代码缓存等。在较老的版本中方法区是基于“”永久代”的概念设计的,在JDK8之后把类型信息放到了直接内存中的元空间(MetaSpace)中,将字符串常量和静态变量等移动到了堆中。

当方法区无法获得新的内存满足需要是,也会抛出OutOfMemeoryError。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值