首页 > 其他分享 >JVM问题总结

JVM问题总结

时间:2024-09-12 16:22:30浏览次数:3  
标签:总结 Java G1 回收 问题 GC 内存 JVM 加载

jvm基础概念

1.1 什么是JVM?

JVM(Java Virtual Machine,Java 虚拟机)是一种运行 Java 字节码的虚拟化平台。JVM 的主要作用是将编译后的 Java 字节码(.class 文件)转换为机器指令,使其能够在不同平台上运行,而不需要修改代码。通过这种机制,Java 实现了“一次编写,处处运行”的跨平台特性。

1.2 jvm的功能

JVM 的关键功能包括:

  1. 解释和执行字节码:JVM 将字节码转换为平台相关的机器指令,并负责执行这些指令。
  2. 内存管理:JVM 提供垃圾回收机制,自动管理内存分配和释放,避免了手动内存管理导致的内存泄漏等问题。
  3. 安全性和隔离:JVM 提供沙箱机制,确保 Java 应用的安全性,避免恶意代码对底层操作系统的直接访问。

JVM 也支持其他编程语言(如 Kotlin、Scala 等),只要这些语言编译后的字节码符合 JVM 规范。

1.3 jvm的组成

JVM(Java 虚拟机)的组成可以分为以下几个主要部分,它们共同负责字节码的加载、解释、执行以及内存管理等工作:

1. 类加载子系统(Class Loader Subsystem)

负责将 Java 字节码(.class 文件)加载到内存中,并且按照需求将类动态加载到 JVM。它的主要任务是查找并加载类文件,并在 JVM 中创建相应的类对象。类加载子系统包括以下三个阶段:

类的生命周期

  • 加载(Loading):读取字节码文件并转换为类的内存表示,javap -v,jclasslib,arthas(dump命令)工具打开。

    类加载器的双亲委派机制:

  • 双亲委派机制的核心思想是:当一个类加载器收到加载类的请求时,它不会立即自己去加载该类,而是将该请求委派给它的父类加载器,父类加载器再将请求委派给它的父类加载器,直到最顶层的根类加载器(通常是引导类加载器,Bootstrap ClassLoader)。如果父类加载器无法完成类的加载,才会让子类加载器自己尝试去加载。

    这种机制保证了类加载的一致性,特别是像 java.lang.Object 这样的核心类,总是由引导类加载器加载,这样可以避免多次加载同一个类或被不可信的类加载器覆盖。

    尽管双亲委派机制是 Java 类加载的一项重要原则,但在某些特殊情况下,可能会被打破,比如:SPI(Service Provider Interface)机制:Java 中的 SPI 机制会用自定义的类加载器来加载服务接口的实现类。OSGi 和 Tomcat 等框架:这些框架有自己的类加载机制,用于实现模块化或动态加载类。

  • 链接(Linking):将类的二进制表示合并到 JVM 中,包括验证、准备和解析。
  • 初始化(Initialization):执行静态初始化器和静态字段赋值。

arthas功能

2. 运行时数据区(Runtime Data Area)

JVM 在执行 Java 程序时使用的内存区域,可以分为以下几个部分:

  • 方法区(Method Area):存储类的结构信息(如字段、方法、常量等)和静态变量。
  • 堆(Heap):存储所有 Java 对象和数组,是 JVM 内存的最大组成部分,由垃圾回收器管理,也可向栈一样设置堆大小,-Xms,一般和栈的容量设置相同的值,避免堆内存的申请和收缩收到影响。
  • 栈(Java Stack)每个线程都会有自己的栈,用于存储栈帧:局部变量、操作数栈、方法调用,异常表,动态链接(帧数据)等,可能会数据溢出,一般为1024的倍数大小,也可以自定义栈内存大小-XSS1g,一般为-xss1k到xss1025m
  • 程序计数器(PC Register):每个线程都有自己的程序计数器,用于指示当前执行的字节码指令地址,不会发生内存溢出的
  • 本地方法栈(Native Method Stack):为调用本地方法(非 Java 编写的方法)提供支持。

3. 执行引擎(Execution Engine)

执行引擎负责执行字节码,它将字节码解释为机器指令并交给 CPU 执行。执行引擎包括:

  • 解释器(Interpreter):逐行解释并执行字节码,速度较慢。
  • 即时编译器(JIT Compiler, Just-In-Time Compiler):将经常执行的字节码编译为机器码,提高执行效率。
  • 垃圾回收器(Garbage Collector)自动管理堆内存,负责回收不再使用的对象,避免内存泄漏。

 内存泄漏指的是不再使用的对象在系统中未被回收,内存泄漏的积累可能会导致内存溢出。

java中为了简化对象的释放,引入了自动的垃圾回收(Garbage Collection简称GC)机制。通过垃圾回收器来对不再使用的对象完成自动的回收,垃圾回收器主要负责对堆上的内存进行回收。其他很多现代语言比如C#、Python、Go都拥有自己的垃圾回收器。 

 

 几种常见的对象引用
可达性算法中描述的对象引用,一般指的是强引用,即是GCRoot对象对普通对象有引用关系,只要这层关系存在普通对象就不会被回收。除了强引用之外,Java中还设计了几种其他引用方式:软引用。弱引用。虚引用。终结器引用。弱引用主要在ThreadLocal中使用。弱引用对象本身也可以使用引用队列进行回收。

4. 本地方法接口(Native Interface)

JNI(Java Native Interface)允许 Java 程序调用本地(Native)代码,比如用 C 或 C++ 编写的程序。通过 JNI,Java 可以与操作系统或硬件进行交互。

5. 垃圾回收(Garbage Collection, GC)

垃圾回收器负责自动管理 JVM 堆内存,跟踪对象的生命周期,并回收不再使用的内存空间。垃圾回收器通常使用算法如标记-清除(Mark-and-Sweep)、复制、分代GC、标记-整理(Mark-and-Compact)等来完成垃圾回收工作。-verbose:gc

1.标记清除

优点:实现简单,只需要在第一阶段给每个对象维护标志位,第二阶段删除对象即可。缺点:1.碎片化问题
由于内存是连续的,所以在对象被删除之后,内存中会出现很多细小的可用内存单元。如果我们需要的是一个比较大的空间,很有可能这些内存单元的大小过小无法进行分配。

2.分配速度慢。由于内存碎片的存在,需要维护一个空闲链表,极有可能发生每次需要遍历到链表的最后才能获得合适的内存空间。

2.复制算法
吞吐量高
复制算法只需要遍历一次存活对象复制到To空间即可,比标记-整理算法少了一次遍历的过程,因而性能较好,但是不如标记-清除算法,因为标记清除算法不需要进行对象的移动


内存使用效率低
每次只能让一半的内存空间来为创建对象使用
不会发生碎片化
复制算法在复制之后就会将对象按顺序放入To空间中,所以对象以外的区域都是可用空间,不存在碎片化内存空间。

3.标记整理算法
内存使用效率高
整个堆内存都可以使用,不会像复制算法只能使用半个堆内存
不会发生碎片化

整理阶段的效率不高
整理算法有很多种,比如Lisp2整理算法需要对整个堆中的对象搜索3次,整体性能不佳。可以通过Two-Finger、表格算法、ImmixGc等高效的整理算法优化此阶段的性能
在整理阶段可以将对象往内存的一侧进行移动,剩下的空间都是可以分配对象的有效空间

G1垃圾回收器(Garbage First Garbage Collector,简称G1 GC)是Java虚拟机的一种高效的垃圾回收算法,主要用于替代传统的CMS(Concurrent Mark-Sweep)收集器。它特别适合处理具有大堆内存和对低停顿时间要求高的应用场景。

G1 GC的特点

  1. 区域划分(Region-based memory layout):

    • 堆内存被划分成多个大小相同的区域(Regions),每个区域可能属于年轻代或老年代,避免了固定代空间大小的限制。
  2. 并发处理:

    • G1能够在执行应用程序的同时进行垃圾回收,减少了应用程序的停顿时间。
  3. 分阶段回收:

    • G1分为几个阶段进行回收:初始标记、并发标记、最终标记、筛选回收。尤其在“并发标记”阶段,GC可以和应用程序并发执行,不会长时间阻塞应用。
  4. 可预测的停顿时间:

    • G1通过目标停顿时间来进行优化,允许开发人员设定一个最大停顿时间的目标,GC会根据此目标调整回收过程中的行为。
  5. 垃圾优先回收:

    • G1根据各个区域的垃圾占比,优先回收垃圾最多的区域,最大限度地提高回收效率。

G1 GC的工作过程

G1 GC的过程可以分为以下几步:

  1. 年轻代垃圾回收(Young GC): 处理年轻代中的对象,对象如果存活会晋升到老年代。

  2. 并发标记(Concurrent Marking): 标记堆内存中的存活对象,计算每个区域的存活对象占比,识别出包含最多垃圾的区域。

  3. 混合回收(Mixed GC): 除了清理年轻代,还会清理一些老年代的区域,尤其是那些垃圾占比高的区域。

  4. 完全回收(Full GC): 当内存使用情况非常紧张时,可能会触发完全回收,但这是G1 GC尽力避免的情况,因为它会导致较长的停顿时间。

G1 GC的调优参数

  • -XX:MaxGCPauseMillis=<N>:设定最大垃圾回收停顿时间的目标(毫秒)。G1 GC会尽量优化以满足这个目标。
  • -XX:InitiatingHeapOccupancyPercent=<N>:在堆内存使用量达到该百分比时开始并发标记阶段,默认是45%。
  • -XX:G1ReservePercent=<N>:保留堆内存的百分比,用于避免在垃圾回收时出现内存不足的情况。

G1 GC非常适合用于处理大规模应用程序,特别是那些对GC停顿时间敏感的场景。

垃圾回收器的组合关系虽然很多,但是针对几个特定的版本,比较好的组合选择如下:
JDK8及之前:
ParNew +CMS(关注暂停时间)Parallel Scavenge + Parallel Old (关注吞吐量)、 G1(JDK8之前不建议,较大堆并且关注暂停时间)
JDK9之后:
G1(默认)
从JDK9之后,由于G1日趋成熟,JDK默认的垃圾回收器已经修改为G1,所以强烈建议在生产环境上使用G1。

标签:总结,Java,G1,回收,问题,GC,内存,JVM,加载
From: https://blog.csdn.net/qq_43062182/article/details/141927407

相关文章

  • 已成功入职字节,总结精选50个大模型高频面试题(附答案)
    觉得中大厂面试太难的,完全就是自己没准备充分,技术不到位,没准备的面试完全是浪费时间,更是对自己的不负责!.今天我给大家分享一下我整理的《精选50个大模型高频面试题》大模型面试专题和答案,其中大部分都是面试常问的面试题,可以对照这查漏补缺奥!祝大家早日上岸呀!1.简述GP......
  • 【学习归纳自我总结版】尚硅谷学习第二天
    数据存储和运算符1.进制1.1进制的分类十进制二进制八进制十六进制数字范围0-90-10-70-9,a-f进位规则逢十进一逢二进一逢八进一逢十六进一示例12501111757F说明每三位二进制是一位八进制值每四位二进制是一位十六进制值1.2在代码中如何表示四种进制的常量值十进制:正常表......
  • HVV行动之蓝军经验总结
    ......
  • 最强Java面试八股文总结,欢迎收藏!
    MySQL八股文 问:Mysql的存储引擎有理解过吗?我比较了解就是Innodb,myisam,Memory。 Innodb:现在的mysql默认存储引擎就是innodb,主要就是因为它是唯一一个支持事务的存储引擎,支持表级锁和行级锁,其索引的底层结构使用的是B+树,在数据,索引,表结构都存储到.idb中。 Myisam:其不支......
  • elasticsearch学习笔记整理(含下面总结的面试题)
    elasticsearch是一个全文检索的搜索引擎Elasticsearch是一个基于Lucene的搜索服务器ES可以做全文检索、模糊查询(搜索)、数据分析(提供分析语法,例如聚合)。es是不能使用root用户进行启动的,要新创建一个用户才行创建用户:useraddqianfeng设置密码:passwdqianfeng早期es的结构......
  • 销售发票过账问题
    SAP消息号K/834对于物料'XXXXX'没有发现标准成本估算具体参考下图:   时间是20240912,发票的请款日期也是当天,MM03查看是有核发标准成本的,也没有标记冻结。查询开票的交货单,有一个交货单的实际交货日期是在20240801,MM03查看物料更改记录(环境->显示更改)。  发现在202......
  • 在CSS中,有哪些常见的选择器优先级问题,应该如何避免?
    在CSS中,有哪些常见的选择器优先级问题,应该如何避免?来源:锦匠网页在CSS中,选择器优先级(也称为特异性)决定了多个规则冲突时,哪个规则将被应用到元素上。理解和正确处理选择器优先级问题对于前端开发者来说非常重要,因为它们直接影响到页面的最终样式。本文将探讨常见的选择器优......
  • 单选和多选在table里的报错问题Blocked aria-hidden on a <input> element because the
    单选在main.js里//table单选报错问题Vue.directive('removeAriaHidden',{bind(el,binding){constariaEls=el.querySelectorAll('.el-radio__original')ariaEls.forEach((item)=>{item.removeAttribute('aria-hidden')......
  • 【项目实战】NIO 与 直接内存 (Direct Memory),由JVM直接管理,而不是通过垃圾回收器来管
    一、技术概览1.1定义直接内存,DirectMemory。直接内存,是指位于Java堆外的一块内存区域。直接内存,由JVM直接管理,而不是通过垃圾回收器来管理。直接内存,可以通过Java的ByteBuffer.allocateDirect()方法创建。直接内存,可以提高数据传输效率,特别是当数据需要频繁地在网络......
  • 移动端web app自适应布局探索与总结
    1、困扰多时的问题在这之前做webapp开发的的时候,在自适应方面一般都是宽度通过百分比,高度以iPhone6跟iPhone5之间的一个平衡值写死,我们的设计稿都是iPhone5的640*1136标准,所以高度一般取个大概值,各种图标的宽高也是取平衡值写死,然后部分样式通过媒体查询来设置,例如背景图的......