0
点赞
收藏
分享

微信扫一扫

JVM内存结构

蒸熟的土豆 2021-09-26 阅读 139
Java

JVM架构

JVM = 类加载器(classloader) + 执行引擎(execution engine) + 运行时数据区(runtime data area)



内存分类

堆内存(Heap)

  • 堆是Java 虚拟机所管理的内存中最大的一块,默认为物理内存1/4大小
  • 堆是被所有线程共享的区域,在虚拟机启动时创建
  • 堆里面存放的都是对象的实例(new 出来的对象都存在堆中)
  • 我们平常所说的垃圾回收,主要回收的就是堆区
  • 默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2
  • 默认的,Eden : From : To = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定 )
Thread Local Allocation Buffer (TLAB,线程本地分配缓冲区)
  • 占用 Eden 区(缺省 Eden 的1%),默认开启,线程私有
  • 优化多线程堆空间分配对象指针碰撞问题

非堆内存(NonHeap)

Metaspace
  • JAVA8以后使用Metaspace替代了PermGen(永久代),将元数据移动到了非堆内存中。默认为物理内存的1/64大小
  • 当一个类被加载时,它的类加载器会负责在 Metaspace 中分配空间用于存放这个类的元数据
  • 只有当这个类加载器加载的所有类都没有存活的对象,并且没有到达这些类和类加载器的引用时,相应的 Metaspace 空间才会被 GC 释放
  • 释放 Metaspace 的空间,并不意味着将这部分空间还给系统内存,这部分空间通常会被 JVM 保留下来
  • Metaspace 可能在两种情况下触发 GC:Metaspace需要扩容时达到MaxMetaspaceSize时,所以通常把-XX:MetaspaceSize和-XX:MaxMetaspaceSize设置为相同的值(Metaspace默认大小只有21MB)
Compressed Class Space
  • 压缩指针,指的是在 64 位的机器上,使用 32 位的指针来访问数据(堆中的对象或 Metaspace 中的元数据)的一种方式
  • 它需要被分配一个连续的地址空间,因此在GC后释放的空间会被JVM保留,一定不会还给物理内存
  • 默认大小是1G,但如果设置了-XX:MaxMetaspaceSize,则它的大小不会超过MaxMetaspaceSize
Direct Memory
  • NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的 I/O 方式,它可以使用 native 函数库直接分配堆外内存,然后通过一个存储在Java堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作
  • 可以帮助JAVA实现零拷贝
  • 默认大小为堆内存大小,可通过-XX:MaxDirectMemorySize设置
  • 不会被GC,使用时要注意释放

线程共享与私有

堆外内存使用指标

usedcapacitycommittedreserved

  • committed、reserved
    committedreserved并不纯粹是JVM的概念,它和操作系统相关。
    reserved是指,操作系统已经为该进程“保留”的。所谓的保留,更加接近一种记账的概念,就是操作系统承诺说一大块连续的内存已经是你这个进程的了。那么实际上这一大块内存有没有真实对应的物理内存,这时是不知道的,等进程committed的时候,进程真的要用这个连续地址空间的时候,操作系统才会分配真正的内存。所以,这也就是意味着,这个过程会失败。

  • used、capacity
    比如创建了一个可以存放20个元素的ArrayList,但是我实际上只放了10个元素,那么capacity就是20,而size就是10,这里的size和used就是一个概念。

Netty直接内存溢出

  • 如果有手工分配了DataBuffer但是没有释放的时候,Netty会报警ByteBuf.release()没有调用。
  • 如果直接内存被占满无法继续分配到内存空间,会报出OutOfDirectMemoryError的异常,大量的请求无法获取内存会导致应用挂掉,无法访问任何接口。


常见调优参数

参数名称 含义 默认值 说明
-Xms   初始堆大小              物理内存的1/64            默认空余堆内存小于40%时(MinHeapFreeRatio),堆增大到-Xmx的值
-Xmx 最大堆大小 物理内存的1/4 默认空余堆内存大于70%时(MaxHeapFreeRatio),堆减小到-Xms的值
-Xmn 年轻代大小 堆内存的1/3 此处的大小是eden+ 2 survivor space,增大年轻代后,将会减小年老代大小
-Xss 每个线程的堆栈大小 1M
-XX:NewRatio 年轻代与年老代的比值 2 -XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5,当Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置
-XX:MetaspaceSize 元空间初始大小 21M 元空间的大小达到这个值时,会触发Full GC并会卸载没有用的类
-XX:MaxMetaspaceSize 元空间最大可分配大小 物理内存的1/64
-XX:MaxDirectMemorySize 直接内存最大可分配大小 与堆内存相同
  • 应用可分配的最大内存

垃圾回收(GC)

GC重点
  • 程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程而灭,因此这几个区域的内存分配和回收都具备确定性,不需要过多考虑如何回收的问题,当方法结束或者线程结束时,内存自然就跟随着回收了。
  • 而Java堆和方法区(元数据区)这两个区域则有着很显著的不确定性,只有处于运行期间,我们才能知道程序究竟会创建哪些对象,创建多少个对象,这部分内存的分配和回收是动态的。垃圾收集器所关注的正是这部分内存该如何管理。
可达性分析法

在Java技术体系里面,固定可作为GC Roots的对象包括以下几种:

  • 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等
  • 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。
  • 在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用
  • 在本地方法栈中JNI(即通常所说的Native方法)引用的对象
  • Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器
  • 所有被同步锁(synchronized关键字)持有的对象
  • 反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等
分代收集理论

当前商业虚拟机的垃圾收集器,大多数都遵循了“分代收集”(Generational Collection)[1]的理论进行设计,分代收集名为理论,实质是一套符合大多数程序运行实际情况的经验法则,它建立在两个分代假说之上:

  • 弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕灭的
  • 强分代假说(Strong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以消亡

在一次次只局限于新生代区域内的收集中,新生代中的对象是完全有可能被老年代所引用的,因此对分代收集理论添加第三条经验法则:

  • 跨代引用假说(Intergenerational Reference Hypothesis):跨代引用相对于同代引用来说仅占极少数

各阶段GC名词:

  • 新生代收集(Minor GC/Young GC):指目标只是新生代的垃圾收集
  • 老年代收集(Major GC/Old GC):指目标只是老年代的垃圾收集。目前只有CMS收集器会有单独收集老年代的行为。Major GC在不同的资料上常有不同所指,需要按照上下文区分到底是指老年代收集还是整堆收集
  • 整堆收集(Full GC):收集整个Java堆和方法区(元数据区)的垃圾收集。
堆内存使用流程

举报

相关推荐

JVM 内存结构

jvm内存结构

java JVM - jvm内存结构

JVM-JVM内存结构(二)

JVM----内存结构

JVM之内存结构

jvm的内存结构

JVM 内存结构简介

0 条评论