JVM相关总结

系列文章目录

文章目录


一、案例

使用阿里的arthas去确认升级完的字节码文件是不是最新的

思路:

在出问题的服务器上部署一个arthas,并启动

连接arthas的控制台,使用jad命令加上想要查看的类名,反编译出源码

确认源码是否是最新的

二、前情提要

1、字节码文件的核心组成有哪些?

基本信息:魔数,字节码文件对应的java版本号,访问标识,父类,接口

常量池:保存了字符串常量,类和接口名,字段名

字段:当前类或者接口声明的字段信息

方法:当前类或者接口的方法信息字节码指令

属性:类的属性,比如源码的文件名,内部类的列表等

2、类的生命周期

2.1 加载

类加载器根据类的全限定名通过不同的渠道 以二进制流的方式获取字节码信息

(本地文件-磁盘上的字节码文件,程序运行时使用动态代理生成的类)

类加载器在加载完类以后,java虚拟机会将字节码中的信息保存到内存的方法去中,生成一个InstanceKlass对象(字节码文件:基本信息,常量池,字段,方法xx),保存类的所有信息,里边还包含实现特定功能比如多态的信息,同时,Java虚拟机还会在堆中生成一份与方法区中数据类似的java.lang.Class对象,

2.2 连接:

验证:验证字节码信息

准备:准备阶段为静态变量分配内存并设置初始值,final修饰的基本数据类型的静态变量,准备阶段直接会将代码中的值进行赋值

解析:将常量池中的符号引用替换为直接引用。符号引用就是在字节码文件中使用编号来访问常量池中的内容,直接引用就是使用内存地址直接访问

2.3 初始化

初始化阶段会执行静态代码块中的代码,并为静态变量赋值

初始化阶段会执行字节码文件中clinit部分的字节码指令

下面几种方式都会导致类的初始化

访问一个类的静态变量或者静态方法,注意变量是final修饰的并且右边是常量不会触发初始化

调用class.forName(xxxxx)

new 一个该类的对象时

执行main方法的当前类

3、类加载器

jdk8和之前的版本:
虚拟机底层实现

启动类加载器:加载java中最核心的类,启动类加载器是由Hotspot虚拟机提供的,使用C++编写的类加载器,默认加载java安装目录下/jre/lib下的类文件,比如rt.jar

java :允许扩展java中比较通用的类, 扩展类加载器和应用程序类加载器都是jdk提供的,使用java编写的类加载器,他们的源码都位于sun.misc.Launcher中,是一个静态内部类。继承自URLClassLoader。具备通过目录或者指定jar包将字节码文件加载到内存中

扩展类加载器:默认加载java安装目录jre/lib/ext下的类文件

应用程序类加载器:加载classpath下的类文件,以及第三方依赖的类文件

4、为什么需要双亲委派机制?

双亲委派指的是:自底向上查找是否加载过, 再由顶向下进行加载(向下委派起到了一个加载优先级的作用),向上查找如果已经加载过,就直接返回class对象,加载过程结束,这样就能避免一个类重复加载

保证类加载的安全性:通过双亲委派机制避免恶意代码替换JDK中的核心类库,比如java.lang.String, 确保核心类库的完整性和安全性

避免重复加载:避免同一个类被加载多次

5、为什么需要打破双亲委派机制?

三种方式:

自定义类加载器: 通过重写loadClass方法,就可以将双亲委派机制的代码去除

线程上下文类加载器:利用上下文类加载器加载类,比如JDBC和JNDI等

osgi框架的类加载器

三、Java中垃圾回收

1、Young GC=年轻代垃圾回收

仅针对新生代(eden区和s0,s1区), 当新生代内存,尤其是eden区被填满时触发,只回收新生代里的对象,老年代不受影响,回收频率较高,回收时间较短,因为新生代对象大多数都是周明周期短,容易被回收

1、Eden区空间不足---触发YGC

新生代被划分为三个区域:Eden区, s0区, s1区, 大部分新创建的对象会先分配到eden区

当eden区的对象填满,无法再为新的对象分配空间时,young gc会被触发,回收新生代中不再使用的对象

2、Eden区+S区都满了----触发YGC

如果eden区和s区的空间都不足以存放新分配的对象时,YGC也会被触发,清理空间并将幸存的对象转移到S区域老年代

3、部分垃圾回收器full gc之前---触发YGC

Parallel Scavenge垃圾回收器在full gc 之前先执行下YGC

2、old GC=老年代垃圾回收

只针对老年代,当老年代空间不足触发,通常是从新生代晋升到老年代对象或多,或者老年代存活对象数量达到一定一定阈值。执行方式是只回收老年代的对象,新生代不受影响,执行时间比young GC长,因为老年代中的对象存活时间长,数量多

3、Full GC=整堆垃圾回收

顾名思义,对整个堆进行回收,当老年代空间不足且取法通过老年代垃圾回收释放足够空间,或其他情况导致系统内存压力较大时触发,回收时间长,会触发整个JVM的停顿,对性能有影响

1、老年代--触发FGC

当老年代空间不足,且无法通过老年代垃圾回收释放足够空间,

2、永久代或者元空间不足

java8以前,如果永久代空间不足,会触发FGC, java8以后,永久代被移除,元空间取代了永久代,如果元空间内存不足,也可能触发FGC

3、调用system.gc, jmap-dump等命令

显示调用system.gc方法。可能会触发FGC

4、新生代晋升到老年代失败

年轻代的大对象或者长期存活的对象被晋升到老年代,如果老年代空间不足,也会触发FGC

四、OOM

oom表示JVM无法为应用程序分配足够的内存,导致程序崩溃

堆内存溢出:

java堆用于存放对象实例,如果创建了过多对象,或者内存泄漏导致对象无法被回收,会导致堆内存耗尽,如果有大量创建对象或者集合类的场景,持续增加数据但是未释放就会产生堆内存溢出

栈内存溢出:

每个线程都会有独立的栈空间,栈用于存储方法调用的信息,局部变量,方法参数等,如果方法调用层次特别深或者有无限递归,栈空间耗尽

方法区或者元空间溢出

java8以后,永久代被替换成元空间,用本地内存实现,在频繁加载和卸载类的情况下,会导致溢出

直接内存溢出

java nio使用直接内存来加快IO操作,该内存不受JVM堆内存的限制,如果分配过多的直接内存,超过了设置的最大值,也会导致内存溢出

线程数过多导致内存溢出

每个线程都需要栈空间和一定的操作系统资源,如果创建过多线程而超出操作系统的资源限制,可能无法再创建新的线程,导致OOM, 应该合理设置线程池的大小,避免无限创建新的线程

GC执行时间太长导致的溢出

五、python中垃圾回收

Python 也有垃圾回收机制(Garbage Collection, GC),但它的实现方式和 Java 的不同。虽然 Java 中有 YGC(Young Generation GC)、Old GC(Old Generation GC) 和 Full GC 等概念,Python 并没有完全相同的分类,但它的垃圾回收机制同样负责自动管理内存,避免内存泄漏

复制代码
Python 使用的是 引用计数(Reference Counting) 作为主要的垃圾回收机制,
同时结合了 分代收集(Generational Garbage Collection) 和 循环检测(Cycle Detection)
 来处理复杂的内存管理问题

1、引用计数(Reference Counting)

每个对象都有一个引用计数器。

当一个对象被引用时,引用计数加一;当引用被移除时,引用计数减一。

当引用计数为 0 时,该对象会被立即回收。

2、分代收集(Generational GC)

Python 将对象分为三个"代":

第 0 代(Generation 0):新创建的对象,频繁回收

第 1 代(Generation 1):在第 0 代中存活下来的对象

第 2 代(Generation 2):在第 1 代中存活下来的对象

与 Java 不同的是,Python 的分代机制不是基于内存区域划分,而是基于对象的生命周期长短。

3、循环检测(Cycle Detection)

对于无法通过引用计数回收的循环引用对象(如两个互相引用的列表),Python 使用 标记-清除(Mark-Sweep) 算法来识别并回收这些对象。

4、触发时机

自动触发:

内存使用达到一定阈值时(由 gc 模块控制)

手动触发

执行 gc.collect() 手动触发

相关推荐
2401_894241921 分钟前
机器学习与人工智能
jvm·数据库·python
vx-程序开发7 分钟前
springboot在线装修管理系统-计算机毕业设计源码56278
java·c语言·spring boot·python·spring·django·php
大傻^10 分钟前
Spring AI Alibaba 可观测性实践:AI应用监控与链路追踪
java·人工智能·后端·spring·springaialibaba
云烟成雨TD15 分钟前
Spring AI Alibaba 1.x 系列【1】阿里巴巴 AI 生态
java·人工智能·spring
佑白雪乐18 分钟前
LCR 175. 计算二叉树的深度
算法·深度优先
诗人不写诗19 分钟前
spring是如何组织切面的
java·后端·spring
阿Y加油吧25 分钟前
力扣打卡day07——最大子数组和、合并区间
算法
想吃火锅100529 分钟前
【leetcode】105. 从前序与中序遍历序列构造二叉树
算法·leetcode·职场和发展
2401_8318249636 分钟前
嵌入式C++驱动开发
开发语言·c++·算法
靠沿38 分钟前
【优选算法】专题十八——BFS解决拓扑排序问题
算法·宽度优先