Java Virtual Machine,即Java虚拟机,缩写JVM,是Java软件运行的平台。
JVM不直接作用于硬件,而是借助操作系统,通过操作系统来作用于硬件。
JVM ↔ 操作系统 ↔ 硬件
在JVM里有堆也有栈。堆是用来存放数据的,是多线程所共享的。栈是代码运行的内容,我们所写的方法,就会在栈里运行。
程序计数器
在讲解硬件CPU的工作原理时,也会出现程序计数器(PC),在CPU中,程序计数器用来存放下一步所执行的指令的地址。
在JVM中,程序计数器扮演类似的角色。程序计数器也是用来存放当前线程下一步执行的字节码指令等信息。每个线程都有独立的程序计数器,这样CPU才能在轮转切换下顺利地回到正确的执行位置。
为了各个线程之间相互不影响,因此JVM将此内存区域设计为线程私有的。
虚拟机栈
JVM的栈也是线程私有的。站用来存储局部变量、操作栈、动态链接、方法出口等信息,它们存在一个名为“栈帧”的数据结构里。
栈的生命周期与线程相同。一个线程在创建时,JVM会为其创建一个专门的栈。线程运行完,栈的生命周期也就结束了,栈所占据的内存空间也会被释放,所以栈无所谓垃圾回收的问题。
补充:
8种基本类型的变量+对象的引用变量+实例方法都是在栈里面分配内存
本地方法栈
用C/C++写的部分,一般是native的方法才涉及。和虚拟机栈一样,这个也是线程私有的。
虚拟机堆
堆是放数据用的,一般来说是JVM中最大的内存区域,如同植物细胞液之于植物细胞。Java在运行期间创建的对象基本上都会放在堆里。
堆会产生垃圾,故而是垃圾回收的重点区域。
堆还可以进一步分类。堆包括“老生代”和“新生代”,其中新生代又包括“Eden区”和“Survivor区”。
新创建的对象会放在Eden区,这里就像产房一样。但是产房容易放满,把确认存活的婴儿送到普通病房。普通病房有两间,分别是 Survivor 0 和 Survivor 1 病房。总是会有一个病房先空着不住人,然后往另一间住婴儿,直到住满为止。如果住满了,就把还存活地移动到另一间病房,这个时候这一间又空了。
连续15次都存活的婴儿,就会被推入老生区了。老生区都是长期存在的对象。
方法区
方法区同样也是被多个线程共享的区域,存放已经被JVM加载的类信息、常量、静态变量、即时编译器等。
方法区的实现取决于JVM,有使用持久区的,也有使用元空间(Meta Space)的。Java 1.8及之后的版本都是使用元空间。
小结
JVM的内存一般分为五个区域。
区域 | 线程拥有 | 作用 | 大小 |
---|---|---|---|
程序计数器 | 线程私有 | 记录下一条指令的地址 | 很小 |
虚拟机栈 | 线程私有 | 存放方法的调用 | 一般 |
本地方法栈 | 线程私有 | C/C++写的native方法 | 一般 |
虚拟机堆 | 共享 | 创建的对象等数据 | 大 |
方法区 | 共享 | 常量、静态变量等 | 一般 |
注意:
- 程序计数器很小,不会溢出内存(Out Of Memory)。
- 虚拟机堆是垃圾回收的重点照顾区域。
- 诸如int等8种基本变量不在堆里,而是在栈里;而常量、静态变量也不在堆里,在方法区。
插图引自 Java运行时数据区域
网友评论