简介

内存区域,也就是 JVM 运转时数据区域,首要描绘内存空间的区分。

内存模型(Java Memory Model,简称 JMM )是界说了线程和主内存直接的笼统联系,即 JMM 界说了 JVM 在计算机内存(RAM)中的作业办法,假如咱们要想深化了解Java并发编程,就要先了解好Java内存模型。

java 内存区域

JDK8 之后的 JVM 布局

Java 内存区域与内存模型

1. 元空间(metaspace):

元空间替代了以前的永久代(PermGen)。

为什么移除永久代?

永久代是一个包括JVM所需数据的池,例如类或办法。

首先,这区域的内存收回目标首要是针对常量池的收回和对类型的卸载,一般来说这个区域的收回效果比较难令人满意。永久代的废物收回和老年代的废物收回是绑定的,一旦其中一个区域被占满,这两个区都要进行废物收回。

在启动时运用-XX:MaxPermSize=xM参数指定永久生成的巨细。此值是静态的,不会从头调整为更改运转时状况。字符串存在永久代,简单形成永久代内存不足,或许当动态加载的类变多时,内存也会添加。这些都很简单形成OOM。

元空间优化了什么?

  • 巨细 – 元空间占用的空间将依据运转时的应用程序需求动态从头计算。当类加载器将加载越来越多的类时,元空间保留的内存将添加(或在某些类数据被废物收集时减少)。
  • 废物收集 – 一旦metaspace的约束到达,metaspace上的废物收集器就开端作业。例如,当废物收回器在这个空间上的活动太重要时,这可能意味着metaspace指定的巨细不足以满意实际状况,或许可能存在一些内存走漏。
  • no klass – 元空间不再包括KlassKlass及其衍生物。在永久代中,这些目标用于描绘描绘最初存储的类的类。这意味着只存储原始类的信息。

字符串常量池、静态变量、被移动到堆中。运转时常量池、类型信息、常量、字段、办法被移动都了元空间中。

Java 内存区域与内存模型

2. 程序计数器: 程序计数器(Program Counter Register)是一个记录着当前线程所履行的字节码的行号指示器。

由于 Java 虚拟机的多线程是经过线程轮流切换并分配处理器履行时间的办法来完结的,在任何一个确定的时刻,一个处理器内核都只会履行一条线程中的指令。

因此,为了线程切换后能康复到正确的履行方位,每条线程都需求有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,咱们称这类内存区域为“线程私有”的内存。

假如线程正在履行的是一个 Java 办法,这个计数器记录的是正在履行的虚拟机字节码指令的地址;假如正在履行的是 Native 办法,这个计数器值则为空(Undefined)。此内存区域是仅有一个在 Java 虚拟机标准中没有规则任何 OutOfMemoryError 状况的区域。

3. java虚拟机栈:

虚拟机栈描绘的是 Java 办法履行的内存模型:每个办法在履行的同时都会创立一个栈帧(Stack Frame,是办法运转时的根底数据结构)用于存储局部变量表、操作数栈、动态链接、办法出口等信息。每一个办法从调用直至履行完结的进程,就对应着一个栈帧在虚拟机栈中入栈到出栈的进程。

4. 本地办法栈:

本地办法栈(Native Method Stack)与虚拟机栈所发挥的作用是十分相似的,它们之间的区别不过是虚拟机栈为虚拟机履行 Java 办法(也就是字节码)服务,而本地办法栈则为虚拟机运用到的 Native 办法服务。

线程开端调用本地办法时,会进入 个不再受 JVM 约束的世界。本地办法能够经过 JNI(Java Native Interface)来拜访虚拟机运转时的数据区,甚至能够调用寄存器,具有和 JVM 相同的能力和权限。 当大量本地办法出现时,势必会削弱 JVM 对体系的控制力,因为它的出错信息都比较黑盒。对内存不足的状况,本地办法栈仍是会抛出 nativeheapOutOfMemory。

5. java堆:

对于大多数应用来说,Java 堆(Java Heap)是 Java 虚拟机所办理的内存中最大的一块。Java 堆是被一切线程同享的一块内存区域,在虚拟机启动时创立。此内存区域的仅有目的就是寄存目标实例,简直一切的目标实例都在这儿分配内存。

Java 内存区域与内存模型

java 内存模型

Java内存模型是同享内存的并发模型,线程之间首要经过读-写同享变量(堆内存中的实例域,静态域和数组元素)来完结隐式通讯。

Java 内存模型(JMM)控制 Java 线程之间的通讯,决定一个线程对同享变量的写入何时对另一个线程可见。

计算机高速缓存和缓存一致性

计算机在高速的 CPU 和相对低速的存储设备之间运用高速缓存,作为内存和处理器之间的缓冲。将运算需求运用到的数据复制到缓存中,让运算能快速运转,当运算结束后再从缓存同步回内存之中。

在多处理器的体系中(或许单处理器多核的体系),每个处理器内核都有自己的高速缓存,它们有同享同一主内存(Main Memory)。

当多个处理器的运算使命都触及同一块主内存区域时,将可能导致各自的缓存数据不一致。

为此,需求各个处理器拜访缓存时都遵从一些协议,在读写时要依据协议进行操作,来保护缓存的一致性。

Java 内存区域与内存模型

VM主内存与作业内存

Java 内存模型的首要目标是界说程序中各个变量的拜访规则,即在虚拟机中将变量(线程同享的变量)存储到内存和从内存中取出变量这样底层细节。

Java内存模型中规则了一切的变量都存储在主内存中,每条线程还有自己的作业内存,线程对变量的一切操作都必须在作业内存中进行,而不能直接读写主内存中的变量。

这儿的作业内存是 JMM 的一个笼统概念,也叫本地内存,其存储了该线程以读 / 写同享变量的副本。

就像每个处理器内核拥有私有的高速缓存,JMM 中每个线程拥有私有的本地内存。

不同线程之间无法直接拜访对方作业内存中的变量,线程间的通讯一般有两种办法进行,一是经过消息传递,二是同享内存。Java 线程间的通讯选用的是同享内存办法,线程、主内存和作业内存的交互联系如下图所示:

Java 内存区域与内存模型

这儿所讲的主内存、作业内存与 Java 内存区域中的 Java 堆、栈、办法区等并不是同一个层次的内存区分,这两者基本上是没有联系的,假如两者一定要勉强对应起来,那从变量、主内存、作业内存的界说来看,主内存首要对应于Java堆中的目标实例数据部分,而作业内存则对应于虚拟机栈中的部分区域。

学习 www.cnblogs.com/czwbig/p/11…