介绍Java内存区域

1. 程序计数器:

  1. 记录下1条须要执行的字节码指令: 分支、循环、跳转、异样解决、线程复原等性能都须要依赖程序计数器;
  2. 线程公有;
    次要有两个作用:

    1. 字节码解释器通过改变程序计数器来顺次读取指令,从而实现代码的流程管制,如:程序、抉择、循环、异样解决。
    2. 在多线程下,记录以后线程执行地位,从而当线程被切换回来的时候可能晓得该线程上次运行到哪了。
    3. 惟一不会呈现 OutOfMemoryError (内存透露) 的内存区域!

2. Java虚拟机栈:

  1. 线程公有
  2. 形容的是 Java 办法执行的内存模型,每次⽅法调用都通过栈传递数据
  3. Java 内存能够毛糙的辨别为堆内存(Heap)和栈内存 (Stack),其中栈就是当初说的虚拟机栈,或者说是虚拟机栈中局部变量表局部。 (实际上,Java 虚拟机栈是由一个个栈帧组成,而每个栈帧中都领有:局部变量表、操作数栈、动静链接、办法进口信息。)

局部变量表次要寄存了编译期可知的各种数据类型(boolean、byte、char、short、int、float、long、double)、对象援用(reference 类型,它不同于对象自身,可能是一个指向对象起始地址的援用指针,也可能是指向一个代表对象的句柄或其余与此对象相干的地位)。

Java 虚拟机栈会呈现两种谬误: StackOverFlowError 和 OutOfMemoryError 。

  1. StackOverFlowError:
    若Java 虚拟机栈的大小不容许动静扩大,当线程申请栈的深度超过以后Java 虚拟机栈的最大深度,就抛出 StackOverFlowError。
  2. OutOfMemoryError:
    若Java虚拟机堆中没有闲暇内存,并且垃圾回收器也无奈提供更多内存的话。就会抛出 OutOfMemoryError。
    Java 办法有两种返回形式,不论哪种返回形式都会导致栈帧被弹出:
  • return 语句。
  • 抛出异样。

3. 本地办法栈

虚拟机栈为虚拟机执行 Java 办法 (也就是字节码)服务,而本地办法栈则为虚拟机应用到的 Native 办法服务。 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一
本地办法被执行的时候,在本地办法栈也会创立一个栈帧,用于寄存该本地办法的局部变量表、操作数栈、动静链接、进口信息。

办法执行结束后相应的栈帧也会出栈并开释内存空间,也会呈现StackOverFlowError 和 OutOfMemoryError 两种谬误

4. 堆

JVM治理的内存中最大的一块,Java堆是所有线程共享的一块内存区域,在虚拟机启动时创立.

  1. 寄存对象实例,简直所有的对象实例以及数组都在这里分配内存。
  2. 从jdk1.7开始曾经默认开启逃逸剖析,如果某些办法中的对象援用没有被返回或者未被里面应用(也就是未逃逸进来),那么对象能够间接在栈上分配内存。
  3. Java堆是GC治理的次要区域,因而也被称作GC 堆(Garbage Collected Heap).从垃圾回收的角度,因为当初收集器根本都采纳分代垃圾收集算法,所以 Java 堆还能够细分为:新生代老年代:再粗疏一点有:Eden 空间、From Survivor、To Survivor 空间等。

新生代:

Eden 区、两个 Survivor 区都属于新生代->依照程序被命名为 s1 和 s2

老年代:

大部分状况,对象都会首先在 Eden 区域调配,在一次新生代GC后,如果对象还存活,则会进入 s1 或者 s2,并且年龄加 1(Eden 区->Survivor 区后对象的初始年龄变为 1),当它的年龄减少到肯定水平(默认为15岁),就会被降职到老年代中。对象降职到老年代的年龄阈值,能够通过参数 -XX:MaxTenuringThreshold 来设置。

几个谬误:
OutOfMemoryError: GC Overhead Limit Exceeded:

当JVM花太多工夫执行GC且只能回收很少的堆空间,就会产生此谬误!

java.lang.OutOfMemoryError: Java heap space:

在创立新对象时, 堆内存空间有余, 会引发java.lang.OutOfMemoryError: Java heap space 谬误。(和本机物理内存无关,和你配置的内存大小无关!)

5. 办法区/元数据区

⽅法区与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息常量动态变量即时编译器编译后的代码等数据。

尽管 Java 虚拟机标准把办法区形容为堆的一个逻辑局部,然而它却有⼀个别名叫做 Non-Heap(非堆),目标应该是与 Java 堆辨别开来。

扩大1. 办法区和永恒代的关系

  1. 办法区是标准,永恒区是HotSpot的实现
    《Java 虚拟机标准》规定了办法区的概念和它的作用,并没有规定如何去实现。
    办法区和永恒代的关系很像 Java 中接口和类的关系,类实现了接口,而永恒代就是 HotSpot 虚拟机对虚拟机标准中办法区的一种实现形式。 也就是说,永恒代HotSpot 的概念,办法区Java虚拟机标准中的定义,是一种标准,而永恒代是一种实现,一个是规范一个是实现,其余的虚拟机实现并没有永恒代这一说法。
  2. Metaspace(元空间)和 PermGen(永恒代)相似,都是对JVM标准中办法区的一种落地实现。

    不过元空间与永恒代之间最大的区别在于:元空间并不在虚拟机中,而是应用本地内存。

    扩大2. 办法区/永恒代/Metaspace

  3. 办法区:(逻辑上)
    逻辑上的货色,是JVM 的标准,所有虚拟机必须恪守的。
    是JVM 所有线程共享的、用于存储类的信息、常量池、办法数据、办法代码等。
  4. 永恒代:(办法区的实现、JDK7及之前、次要是和元空间比照)
    PermGen , 就是 PermGen space ,全称是 Permanent Generation space ,是指内存的永恒保留区域。PermGen space 则是 HotSpot 虚拟机基于JVM标准对办法区的一个落地实现,并且只有 HotSpot 才有 PermGen space。而如 JRockit(Oracle)、J9(IBM) 虚拟机有办法区 ,然而就没有 PermGen space。PermGen space 是JDK7及之前, HotSpot虚拟机对办法区的一个落地实现。在JDK8被移除。‘
  5. Metaspace(元空间、JDK8及之后):
    元空间与永恒代之间最大的区别在于:元空间并不在虚拟机中,而是应用本地内存

应用本地内存有什么益处呢?最间接的体现就是OOM问题将不复存在,因为默认的类的元数据调配只受本地内存大小的限度,也就是说本地内存残余多少,实践上Metaspace就能够有多大,这解决了空间有余的问题。不过,让Metaspace变得无限大显然是不事实的,因而咱们也要限度Metaspace的大小:应用-XX:MaxMetaspaceSize参数来指定Metaspace区域的大小。JVM默认在运行时依据须要动静地设置MaxMetaspaceSize的大小。

移除PermGen(永恒代)从从JDK7 就开始。例如,字符串外部池,曾经在JDK7 中从永恒代中移除。直到JDK8 的公布将宣告 PermGen(永恒代)的终结。
其实,移除 PermGen 的工作从 JDK7 就开始,永恒代的局部数据就曾经转移到了 Java Heap 或者是 Native Heap。
但永恒代仍存在于JDK7 中,并没齐全移除,比方:
字面量 (interned strings)转移到 Java heap;
类的动态变量(class statics)转移到Java heap ;
符号援用(Symbols) 转移到 Native heap ;
JDK版本办法区的实现运行时常量池所在的地位
JDK6PermGen space(永恒代)PermGen space(永恒代)
JDK7PermGen space(永恒代)Heap(堆)
JDK8Metaspace(元空间)Heap(堆)

字符串外部池,曾经在JDK7 中从永恒代中移除(在堆中)-jdk7中曾经是了.
JDK6、JDK7 时,办法区 就是 PermGen(永恒代)。
JDK8 时,办法区就是 Metaspace(元空间)。

扩大3. 字符串常量池在哪

  1. jdk6->PermGen永恒代
  2. jdk7/jdk8->Heap堆内存