JVM内存模子怎样分配的?

计算机软件开发 2024-10-1 20:57:25 42 0 来自 中国
01 JVM内存模子的划分

由于我们生产环境利用的捏造机HotSpot 居多,以是下面的描述都是基于HotSpot 捏造机而言的,对于其他范例的捏造机,如 JRockit(Oracle)、J9(IBM) 大概并不太一样
根据捏造机规范,JVM的内存分为 堆、捏造机栈、本地方法栈、步伐计数器、本地方法栈5部门
JDK 1.8 同 JDK 1.7 比,最大的差异就是:元数据区取代了永世代。元空间的本质和永世代类似,都是对 JVM 规范中方法区的实现。不外元空间与永世代之间最大的区别在于:元数据空间并不在捏造机中,而是利用本地内存
1.png 1.1 捏造机栈

每个线程有一个私有的栈,随着线程的创建而创建。栈内里存着的是一种叫“栈帧”的东西,每个方法会创建一个栈帧,栈帧中存放了局部变量表(根本数据范例和对象引用)、操作数栈、方法出口等信息。栈的巨细可以固定也可以动态扩展。当栈调用深度大于JVM所答应的范围,会抛出StackOverflowError的错误
捏造机栈的特点

  • 局部变量表随着栈帧的创建而创建,它的巨细在编译时确定,创建时只需分配事先规定的巨细即可。在方法运行过程中,局部变量表的巨细不会发生改变
  • Java 捏造机栈也是线程私有,随着线程创建而创建,随着线程的竣事而烧毁
  • Java 捏造机栈会出现两种非常:StackOverFlowError (若 Java 捏造机栈的巨细不答应动态扩展,那么当线程哀求栈的深度高出当前 Java 捏造机栈的最大深度时,抛出 StackOverFlowError 非常)和 OutOfMemoryError(若答应动态扩展,那么当线程哀求栈时内存用完了,无法再动态扩展时,抛出 OutOfMemoryError 非常)
1.2 本地方法栈

本地方法栈是为 JVM 运行 Native 方法准备的空间,由于许多 Native 方法都是用 C 语言实现的,以是它通常又叫 C 栈。它与 Java 捏造机栈实现的功能类似,只不外本地方法栈是描述本地方法运行过程的内存模子。本地方法被实行时,在本地方法栈也会创建一块栈帧,用于存放该方法的局部变量表、操作数栈、动态链接、方法出口信息等。方法实行竣事后,相应的栈帧也会出栈,并开释内存空间。也会抛出 StackOverFlowError 和 OutOfMemoryError 非常。
1.3 PC 寄存器计数器

PC 寄存器,也叫步伐计数器。JVM支持多个线程同时运行,每个线程都有本身的步伐计数器。倘若当前实行的是 JVM 的方法,则该寄存器中生存当前实行指令的所在;倘若实行的是native 方法,则PC寄存器中为空
1.4 堆

堆内存是 JVM 全部线程共享的部门,在捏造机启动的时间就已经创建。全部的对象和数组都在堆上举行分配。这部门空间可通过 GC 举行接纳。当申请不到空间时会抛出 OutOfMemoryError
堆的特点:

  • 线程共享,整个 Java 捏造机只有一个堆,全部的线程都访问同一个堆。而步伐计数器、Java 捏造机栈、本地方法栈都是一个线程对应一个
  • 在捏造机启动时创建
  • 垃圾接纳的重要场合
  • 可分为:新生代(Eden区 From Survior To Survivor)、老年代
1.5 方法区


  • Java 捏造机规范中界说方法区是堆的一个逻辑部门。
  • 方法区也是全部线程共享。重要用于存储已经被捏造机加载的类的信息、常量池、方法数据、方法代码等。方法区逻辑上属于堆的一部门,但是为了与堆举行区分,通常又叫 非堆 。必要注意的是,方法区只是规范上面的一个逻辑概念,并不是真实的物理存储的定名
1.6 直接内存(堆外内存)

直接内存是除 Java 捏造机之外的内存,但也大概被 Java 利用,直接内存的巨细不受 Java 捏造机控制,但既然是内存,当内存不敷时就会抛出 OutOfMemoryError 非常
直接内存与堆内存比力:

  • 直接内存申请空间泯灭更高的性能
  • 直接内存读取 IO 的性能要优于平常的堆内存
02 JVM内存模子各部门的存储信息

03 针对JDK6、JDK7、JDK8三个版本的JVM内存模子调讲授明

3.1 对永世代PermGen的说明


  • 永世代是方法区在hotspot的一个详细实现。通过在运行时数据区域开发空间实现方法区。
  • hotspot jdk7 之前的永世代,比力完整
  • 从jdk7以后方法区就“四分五裂了”,不再是在单一的一个去区域内举行存储
  • 在jdk8,移除了永世代,被Metsspace取代了,且Metsspace不在JVM堆内,放入了本地内存,元空间也就成了方法区的重要存放位置
绝大部门 Java 步伐员应该都见过 java.lang.OutOfMemoryError: PermGen space这个非常
这里的 “PermGen space”实在指的就是方法区。不外方法区和“PermGen space”又有着本质的区别。前者是 JVM 的规范,而后者则是 JVM 规范的一种实现,而且只有 HotSpot 才有 “PermGen space”,而对于其他范例的捏造机,如 JRockit(Oracle)、J9(IBM) 并没有“PermGen space”。由于方法区重要存储类的相干信息,以是对于动态天生类的环境比力轻易出现永世代的内存溢出。最典范的场景就是,在 jsp 页面比力多的环境,轻易出现永世代内存溢出
3.2 对Metaspace元空间的说明

元空间的本质和永世代类似,都是对JVM规范中方法区的实现。元空间通过在本地内存区域开发空间实现方法区元空间并不在捏造机中,而是利用本地内存,以是默认环境下,元空间的巨细仅受本地内存限定,但可以通过以下参数来指定元空间的巨细:
-XX:MetaspaceSize,初始空间巨细,到达该值就会触发垃圾网络举行范例卸载,同时GC会对该值举行调解:假如开释了大量的空间,就得当低落该值;假如开释了很少的空间,那么在不高出MaxMetaspaceSize时,得当进步该值。-XX:MaxMetaspaceSize,最大空间,默认是没有限定的。除了上面两个指定巨细的选项以外,另有两个与 GC 相干的属性:-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,淘汰为分配空间所导致的垃圾网络-XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,淘汰为开释空间所导致的垃圾网络实在,移除永世代的工作从JDK1.7就开始了,JDK1.7中,存储在永世代的部门数据就已经转移到了Java Heap大概是 Native Heap。但永世代仍存在于JDK1.7中,并没完全移除。
譬如:

  • 符号引用(Symbols)转移到了native heap;
  • 字面量(interned strings)转移到了java heap;
  • 类的静态变量(class statics)转移到了java heap
3.3 元空间特点


  • 类及相干的元数据的生命周期与类加载器的划一,假如GC发现某个类加载器不再存活了,才会把相干的空间整个接纳掉
  • 每个类加载器有专门的存储空间
  • 只举行线性分配,省掉了GC扫描及压缩的时间
  • 元空间里的对象的位置是固定的
04 JVM内存划分调解的几个缘故原由点分析


  • 字符串存在永世代中,轻易出现性能标题和内存溢出
  • 类及方法的信息等比力难确定其巨细,因此对于永世代的巨细指定比力困难,太小轻易出现永世代溢出,太大则轻易导致老年代溢出
  • 永世代会为 GC 带来不须要的复杂度,而且接纳服从偏低
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-18 16:46, Processed in 0.181864 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表