小伙伴们在面试的时候可能都会碰到这样一个问题

面试官问:“你给我讲一下JVM中线程共享/线程独立区域吧”

 不要慌~~   让我们现在来复习一下这部分的知识🤩~~

java线程间共享 jvm中线程共享_java

 我们先来看一下JVM主要分哪几块区域:

java线程间共享 jvm中线程共享_java_02

很容易就能理解,线程独占指每一个线程都有自己独立的内存区域,而这一块内存区域可以分为虚拟机栈,本地方法栈和程序计数器,一个进程可以拥有多个线程,而一个进程对应一个JVM实例,故这些线程必然存在共享的内存空间,这块内存空间又可以分为堆和方法区。

目录

一、程序计数器

二、虚拟机栈

三、本地方法栈

终于来到了线程共享区域了!!!🥳🥳

四、堆

如何在Idea中设置堆的大小呢? (仅做了解哈~😛)

五、方法区


让我们先来看看线程独占区域。

一、程序计数器

        我们直到,在一个CPU内核中,线程并不是并发执行的,而是并行执行的,即在一个CPU内核中,CPU会不停的切换线程以执行所有的程序。

  那当CPU再次切换到某个线程时,它是怎么知道当前的线程上次执行到哪了?

这就是程序计数器的作用,程序计数器中保存了下一条执行的指令的地址,这样当CPU再次切换到此线程时,CPU就可以读取程序计数器中保存的下一条要执行的指令的地址,执行下一条指令。也因为其保存的时下一条执行的指令的地址,所以它必须也必然是线程独占的

(毕竟每条线程都有每条线程自己要干的事情🧐)

二、虚拟机栈

虚拟机栈中保存了此线程拥有的局部变量表(基础数据类型和对象引用地址)和计算过程中产生的中间结果,并参与方法的调用和返回。所以它必然也是线程独占的。

        Java虚拟机栈可以是固定大小,也可以根据计算动态扩展和收缩,我们可以对Java虚拟机栈进行初始值大小的设置,以及最大值的设置。


Java虚拟机栈大小的设置:(了解,不敢兴趣的童鞋可以自行跳过这段🤪🤪~~)

首先我们可以从Oracle官方文档中看到(此为Java 8官方文档,不同JDK可能会有所不同):

java线程间共享 jvm中线程共享_方法区_03

很容易就能看出,我们可以使用-Xss size指令或者-XX:ThreadStackSize=size来指定JVM虚拟机栈的大小。

在Idea中,我们可以这样设置JVM虚拟机栈的大小:

java线程间共享 jvm中线程共享_面试_04

java线程间共享 jvm中线程共享_java线程间共享_05

根据自己心情 根据业务需求设置大小,如果设置过小(就像上面写的10k),则:

java线程间共享 jvm中线程共享_面试_06

 由此我们也可以看到,在Java 8中,Java虚拟机栈最小大小为108k!🤩🤩🤩

而当我们设置一个正常的数字的时候,例-Xss1024K,我们可以在控制台中看到:

java线程间共享 jvm中线程共享_java_07

 此时即为设置成功!🥳


当虚拟机栈出现异常时,有两种情况

  1. 当Java虚拟机栈大小固定时,如果程序中的栈分配超过了设置的最大限度,则会出现StackOverflowError异常。
  2. 若Java虚拟机栈时动态扩展的,则当内存不足时,会引发OutOfMemoryError异常(OOM)。

三、本地方法栈

本地方法栈中保存了此线程使用本地方法(用非Java语言编写的方法)时拥有的局部变量表(基础数据类型和对象引用地址)和计算过程中产生的中间结果,并参与方法的调用和返回。


终于来到了线程共享区域了!!!🥳🥳

四、堆

        堆是JVM所管理的最大内存区域,程序中所有类实例和数组的内存都存储在此区域。堆在程序开始运行时创建,随着程序的退出而销毁,堆中的数据只要还在使用,就不会被销毁。堆的大小可以是固定的,也可以动态扩展和收缩。我们也可以对堆进行初始大小的控制。

java线程间共享 jvm中线程共享_java线程间共享_08

java线程间共享 jvm中线程共享_面试_09

java线程间共享 jvm中线程共享_面试_10

 由官方文档我们可以看出:

1.-Xmn size可以设置堆的初始大小和最大大小

2.-XX:NewSize= 可以设置堆的初始大小

3.-XX:MaxNewSize= 可以设置堆的最大大小

4.-Xms size可以设置堆的最小大小和初始大小(它必须大于等于1M)

5.-Xmx size可以设置堆的最大大小(它必须大于等于2M)

而一旦堆区中的内存大小超过了设置的最大内存大小,则会抛出OutOfMemoryError。

java线程间共享 jvm中线程共享_面试_11

java线程间共享 jvm中线程共享_java线程间共享_12


如何在Idea中设置堆的大小呢? (仅做了解哈~😛)

其实和上面设置栈的大小的方式一致

java线程间共享 jvm中线程共享_面试_04

java线程间共享 jvm中线程共享_面试_14


五、方法区

方法区也是线程共享的,其存储每个类的结构,如运行时常量池,静态变量,字段和方法数据,以及方法和构造函数的代码。

        方法区也是在Java虚拟机启动时而创建的,尽管方法区在逻辑上是堆的一部分,但可以选择不进行垃圾回收或者压缩。方法区可以是固定大小,也可以动态扩展,方法区的内存也不需要连续。我们也可以堆虚拟机的初始大小进行控制,或者在可变大小的方法区中,对其最小内存空间以及最大内存空间进行控制。

所以当方法区内存超过了设置的最大内存空间是,也会报OutOfMemoryError。

(这里就不对如何控制方法区大小进行介绍了,因为我懒吧🤐)

对于HotSpot虚拟机(是Sun JDK和Open JDK中自带的虚拟机,也是目前使用范围最广的Java虚拟机)来说,不同的JDK方法区的实现是不同的,在JDK 1.7之前,HotSpot技术团队使用的是永久代来实现方法区的(此实现方式更容易造成内存溢出),而在JDK 1.8之后,HotSpot虚拟机开始使用元空间来实现方法区了。