JVM

JVM内存模型

 

 

 

Java内存模型规定所有变量都存储在主内存中,每个线程还有自己的工作内存

JMM决定一个线程对变量的写入何时对另一个线程可见。

 

GC回收算法

1、复制清除算法 Copinng

​ 将内存划分为两部分,每次使用一部分,将存活的对象复制到另一部分,再将该部分对象清除

​ 可用内存小

 

 

2、标记清除算法 Mark-Sweep

​ 分为标记阶段和清除阶段,本次标记,下次清除

​ 内存碎片化

 

 

3、标记整理算法 Mark-Compact

​ 将存活对象移动到一边,清除这个边界以外的对象

​ 若移动次数多,效率低

 

 

4、分代收集算法

 

GC垃圾回收

GC:负责无用数据回收的垃圾回收器

可达性分析算法:通过GC Root对象作为起点进行搜索,如果GC Root和一个对象之间没有可达路径,则该对象是不可达的。不可达对象不一定成为可回收对象

 

JVM内存结构五大区域

 

 

 

程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作

 

程序计数器:当前线程执行的字节码行号指示器。(私有)【不会有内存溢出问题】

由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一个线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

 

栈:(先进后出)

由于在HotSpot虚拟机中并不区分虚拟机栈和本地方法栈,因此,对于HotSpot来说,虽然-Xoss参数(设置本地方法栈大小)存在,但实际上是无效的,栈容量只由-Xss参数设定

 

如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常

如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常

虚拟机栈:每个方法执行的时候都会创建栈帧

栈帧:局部变量,操作数栈,动态链接,方法出口

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址。

其中64位长度的long和double类型的数据会占用2个局部变量空间(Slot),其余的数据类型只占用1个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小

 

本地方法栈:被native修饰的方法(非java语言实现的方法)

 

 

 

方法区:(是各个线程共享的内存区域)

它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

 

 

运行时常量池:Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

 

堆:(是垃圾收集器管理的主要区域,因此很多时候也被称做“GC堆”)

Java堆用于存储对象实例,只要不断地创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。

(将堆的最小值-Xms参数与最大值-Xmx参数设置为一样即可避免堆自动扩展)

 

XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照以便事后进行分析

 

垃圾回收算法

可达性分析算法:这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的

gc root根节点:虚拟机栈中引用的对象、方法区中静态属性引用的对象、方法区中常量引用的对象、本地方法区中native引用的对象

判定对象是否存活都与“引用”有关

强引用:在程序代码之中普遍存在的,类似“Object obj = newObject()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。

软应用:用来描述一些还有用但并非必需的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。

弱引用:用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象

虚引用:它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知

 

STW(stop the word):可达性分析对执行时间的敏感还体现在GC停顿上,因为这项分析工作必须在一个能确保一致性的快照中进行——这里“一致性”的意思是指在整个分析期间整个执行系统看起来就像被冻结在某个时间点上,不可以出现分析过程中对象引用关系还在不断变化的情况,该点不满足的话分析结果准确性就无法得到保证。

 

堆的内存划分

 

 

 

1)Minor GC:从年轻代(包括Eden、Survivor区)回收内存。

​ A、当JVM无法为一个新的对象分配内存的时候,越容易触发Minor GC。所以分配率越高,内存越来越少,越频繁执行Minor GC​ B、执行Minor GC操作的时候,不会影响到永久代(Tenured)。从永久代到年轻代的引用,被当成GC Roots,从年轻代到老年代的引用在标记阶段直接被忽略掉。

2)Major GC:清理整个老年代,当eden区内存不足时触发。

3)Full GC:清理整个堆空间,包括年轻代和老年代。当老年代内存不足时触发

 

 

 

JVM优化

  • 年轻对象放在eden区,当第一次GC后,如果对象还存活,放到survivor区,此后,每GC一次,年龄增加1,当对象的年龄达到阈值,就被放到tenured老年区。-XX:MaxTenuringThreshold阈值设置。如果想让对象留在年轻代,可以设置比较大的阈值。

  • 通过设置合理的eden区,survivor区及使用率,可以将年轻对象保存在年轻代,从而避免full GC,使用-Xmn设置年轻代的大小

  • 占用内存比较多的对象,在老年代为其分配内存。若在年代为其分配内存,年轻代内存不够,就要在Eden区移动大量对象到老年代,但这些对象可能很快消亡,导致 full GC

  • 设置最小堆和最大堆:-Xmx-Xms稳定的堆大小堆垃圾回收是有利的。

    • 获得一个稳定的堆大小的方法是设置-Xms和-Xmx的值一样,即最大堆和最小堆一样,如果这样子设置,系统在运行时堆大小理论上是恒定的,稳定的堆空间可以减少GC次数,因此,很多服务端都会将这两个参数设置为一样的数值。

    • 稳定的堆大小虽然减少GC次数,但是增加每次GC的时间,因为每次GC要把堆的大小维持在一个区间内。

  • 一个不稳定的堆并非毫无用处。在系统不需要使用大内存的时候,压缩堆空间,使得GC每次应对一个较小的堆空间,加快单次GC次数。基于这种考虑,JVM提供两个参数,用于压缩和扩展堆空间。

    • -XX:MinHeapFreeRatio 参数用于设置堆空间的最小空闲比率。默认值是40,当堆空间的空闲内存比率小于40,JVM便会扩展堆空间

    • -XX:MaxHeapFreeRatio 参数用于设置堆空间的最大空闲比率。默认值是70, 当堆空间的空闲内存比率大于70,JVM便会压缩堆空间。

    • 当-Xmx和-Xmx相等时,上面两个参数无效

  • 通过增大吞吐量提高系统性能,可以通过设置并行垃圾回收收集器。

    • -XX:+UseParallelGC:年轻代使用并行垃圾回收收集器。这是一个关注吞吐量的收集器,可以尽可能的减少垃圾回收时间。

    • -XX:+UseParallelOldGC:设置老年代使用并行垃圾回收收集器。

  • 尝试使用大的内存分页:使用大的内存分页增加CPU的内存寻址能力,从而系统的性能。-XX:+LargePageSizeInBytes 设置内存页的大小

  • 使用非占用的垃圾收集器。-XX:+UseConcMarkSweepGC老年代使用CMS收集器降低停顿。

  • -XXSurvivorRatio=3,表示年轻代中的分配比率:survivor:eden = 2:3

  • JVM性能调优的工具:

    • jps(Java Process Status):输出JVM中运行的进程状态信息(现在一般使用jconsole)

    • jstack:查看java进程内线程的堆栈信息。

    • jmap:用于生成堆转存快照

    • jhat:用于分析jmap生成的堆转存快照(一般不推荐使用,而是使用Ecplise Memory Analyzer)

    • jstat是JVM统计监测工具。可以用来显示垃圾回收信息、类加载信息、新生代统计信息等。

    • VisualVM:故障处理工具

 

类加载机制

加载 验证 准备 解析 初始化 使用 卸载

在某些情况下,可以在初始化之后解析(支持java运行时绑定、动态绑定)

 

posted @   usersuansuan  阅读(43)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示