本文章内容来自《深入理解jvm虚拟机》一书,有兴趣的同学可以看下这本书。
Java虚拟机在执行Java程序的过程中会将自身所管理的内存划分为若干个不同的数据区。这些区域都有各自的用途,以及创建和销毁的时间。
内存模块大致如下(该图依据《深入理解Java虚拟机一书》)
列个表格介绍每个内存区域的作用以及生命周期
内存类型 | 作用 | 有无异常 | 占用区域大小 | 创建时机&生命周期 | |
---|---|---|---|---|---|
程序计数器 | 记录当前线程中程序执行的位置(大白话就是代码走到那一行了) | 无 | 较小 | 随线程创建而创建,随线程销毁而销毁,生命周期同线程。该区域是线程私有内存,各线程之间相互独立。 | |
虚拟机栈 | 用于承载java方法执行所创建的栈帧从入栈到出栈时所使用的数据(局部变量表...) | OutOfMemoryError和StackOverflowError | -- | 线程私有,同程序计数器 | |
本地方法栈 | 与虚拟机栈相似,只不过是本地方法的执行 | OutOfMemoryError和StackOverflowError | -- | 同虚拟机栈 | |
Java 堆 | 存放对象实例(包含数组) | OutOfMemoryError | 最大 | 线程共享,虚拟机启动时创建, | |
方法区 | 用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码数据等 | OutOfMemoryError | -- | 线程共享的内存区域 | |
运行时常量池 | 是方法区的一部分,用于存放编译期生成的各种字面量和符号引用 | OutOfMemoryError | -- | -- |
有些表格没有列出来的或者其他我需要知道的点,在下面的文字中进行描述
1. 程序计数器
当前线程所执行字节码的行号指示器,字节码指示器通过改变这个计数器的值来选取下一条字节码的指令来驱动程序的执行。
java虚拟机的多线程是通过线程轮流切换并分配时间片的方式实现,任何一个确定的时刻,一个处理器都只会执行一条线程中的指令。
2. Java虚拟机栈
虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时会创建一个栈帧用于存放该方法执行时所需要的数据(局部变量表、操作数栈、动态链接、方法出口等信息)。每个方法从调用直至执行结束的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
局部变量表:
局部变量表所存放的内容是编译期可知的各种基本类型,对象引用类型。(这里可以想一下平时写方法时,方法所包含的内容,局部变量(基本数据类型、引用类型、调用其他方法的返回值)也不知道这样想对不对,有错误欢迎指正)
局部变量表所需要的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变其大小。(讲一个比较容易记的例子,把栈帧当做一个房子(不带车库,但是想买一辆车,需要根据车的尺寸建个车库),这个局部变量表比作车库,那我建车库的时候这些尺寸都是可已知的--有点不恰当,后面在组织下语言,先记着)
3. Java堆
Java堆是垃圾收集器管理的主要区域,可以是物理上不连续的内存空间,逻辑上连续即可。该区域既可以固定大小也可以进行扩展