<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>JVM on Tequila's 学习笔记</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/d-64f7ab1c4a97853c/</link><description>Recent content in JVM on Tequila's 学习笔记</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>© 2026 Tequila</copyright><atom:link href="https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/d-64f7ab1c4a97853c/index.xml" rel="self" type="application/rss+xml"/><item><title>1. 内存区域</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/d-64f7ab1c4a97853c/n-bb6a8ee5de4216dc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/d-64f7ab1c4a97853c/n-bb6a8ee5de4216dc/</guid><description>1 运行时数据区 # 1.1 程序计数器 # 程序计数器可以看作是当前线程所执行的字节码的行号指示器。它通过标示下一条需要执行的字节码指令完成指令切换，可以说一个线程的运行就是在该计数器的不断变化推动下一步一步完成的。
1.2 虚拟机栈 # 虚拟机栈的操作只有两个，就是入栈和出栈。当调用一个新的方法时，就构建一个栈帧压入到栈中，而一个方法执行结束，就会有一个栈帧出栈，整个遵循“先进后出/后进先出”的原则。栈帧中主要存储了局部变量表、操作数栈、动态连接、方法出口等信息 1.3 本地方法栈 # 一个 Native Method 就是一个 Java 调用非 Java 代码的接口。我们知道的 Unsafe 类就有很多本地方法。本地方法栈(Native M ethod Stacks)与虚拟机栈所发挥的作用是非常相似的，其区别只是虚拟机 栈为虚拟机执行Java方法(也就是字节码)服务，而本地方法栈则是为虚拟机使用到的本地(Native) 方法服务。
1.4 Java堆 # Java堆是被所有线程共享的一块内存区域，“几乎”所有的对象实例都在这里分配内存。Java堆也是垃圾收集器管理的内存区域，以G1收集器的出现为分界，往前的收集器基本是采用分代收集理论进行设计，所以“新生代”“老年代”“永久代”“Eden空间”“From Survivor空 间”“To Survivor空间”等概念都是分代设计下的产物，后面会介绍。（​JVM-垃圾收集器与内存分配策略 ），垃圾分代的唯一目的就是优化GC性能。
1.5 方法区 # 方法区(Method Area)与Java堆一样，是各个线程共享的内存区域，它用于存储已被虚拟机加载 的类信息、常量、静态变量、即时编译器编译后的代码缓存等数据。​
运行时常量池（Runtime Constant Pool）是方法区的一部分。Class 文件中除了有类的版本/字段/方法/接口等描述信息外，还有一项信息是常量池表（Constant Pool Table），用于存放编译期生成的各种字面量和符号引用，这部分内容将在类加载后进入方法区的运行时常量池中存放，JVM 为每个已加载的类型（类或接口）都维护一个运行时常量池，在加载类和接口到虚拟机后创建。</description></item><item><title>2. GC</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/d-64f7ab1c4a97853c/n-8fc6cd00a16dd2c0/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/d-64f7ab1c4a97853c/n-8fc6cd00a16dd2c0/</guid><description>引用 # 强引用：是最常见的引用类型，比如Object obj=new Object()这种new产生的引用就是强引用，一个对象如果还有强引用，那么垃圾回收器绝不会回收它。（用途：对象的一般状态）​
软引用：软引用来表示对象是有用的，但不是必须的。如果一个对象只有软引用了，那么当内存不足，准备抛出内存溢出异常以前，会先把这些软引用的对象进行回收了，如果回收之后内存还是不够，这时才实际抛出内存溢出异常。（用途：对象缓存）
弱引用：弱引用就更低一级，用来描述一些非必须的对象。当一个对象只有弱引用的时候，只要发生垃圾回收gc，就会被回收。所以弱引用对象活不过下一次gc; （用途：对象缓存）
虚引用：最弱的一种引用，形同虚设。一个对象是否有虚引用的存在，完全不会对其生存时间构成影响，也无法通过虚引用来取得一个对象实例。为一个对象设置虚 引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。虚引用必须和引用队列关联使用，当垃圾回收器准备回收一个对象时，如果发现它还有虚引用，就会把这个虚引用加入到与之关联的引用队列中。
可达性分析算法 # 通过 一系列称为“GC Roots”的根对象作为起始节点集，从这些节点开始，根据引用关系向下搜索，搜索过程所走过的路径称为“引用链”(Reference Chain)，如果某个对象到GC Roots间没有任何引用链相连， 即GC Roots到这个对象不可达时，则证明此对象是不可能再被使用的。
记忆集 Remembered Sets 简介​
当对堆进行部分内存区域回收的时候，就会存在跨区域引用的问题，在GC Roots这里讲过，如果存在跨区域的引用关系，那么这种引用即便不是“固定”Gc Roots范畴，那也应该纳入作为Gc Roots集合的补充，一起来进行可达性分析判断。（ 例如所有堆内存的被划分为（A,B,C,D,E）五个区，当我们这次只对A，B进行回收时，就需要判断C,D,E中是否有引用A,B中的对象）​
为了能够找出这种跨区的引用关系，一种直接的方式就是，将“回收区”以外的所有内存区域扫描一遍，看看哪些是有引用回收区里面的对象的。很显然，这种全域扫描的方式性能会极差，是不可接受的。所以就有了记忆集，记忆集列出了从外部指向本块的所有引用。 这种引用记录会在引用关系创建，更改时进行维护。当需要进行这种外部引用关系分析时，直接读取记忆集内容就行。
垃圾收集算法 # 1. 标记-清除算法 # 2. 标记-整理算法 # 3. 复制 # 4. 分代收集 # 一般将堆分为新生代和老年代，新生代每次垃圾收集时都发现有大批对象死去，而每次回收后存活的少量对象，将会逐步晋升到老年代中存放​
新生代: ​
绝大多数对象都是朝生夕灭的​ 复制算法​ 老年代: ​
“大多数”是熬过越多次垃圾收集过程的对象。​ 标记 - 清除 或者 标记 - 整理 算法 垃圾收集器 # 3.1 Serial收集器
Serial 翻译为串行，也就是说它以串行的方式执行​ Serial 是新生代的垃圾收集器​ 算法：复制算法 3.</description></item><item><title>3. 类文件结构</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/d-64f7ab1c4a97853c/n-49c52f8a8502e512/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/d-64f7ab1c4a97853c/n-49c52f8a8502e512/</guid><description>任何一个Class文件都对应着唯一的一个类或接口的定义信息，但是反过来说，类或接口并不一定都得定义在文件里；另外Class文件是一组以8个字节为基础单位的二进制流，各个数据项目严格按照顺序紧凑的排列在class文件中，这个二进制流可以不一定来自于磁盘文件，也可以来自于网络，或者动态生成。​
常量池​
访问标志​：描述这个Class是类还是接口;是否定义为public类型;是否定义为abstract 类型;如果是类的话，是否被声明为final，是否为注解，是否为枚举值
类索引，父类索引，接口索引：主要确定该类型的继承关系，即继承了哪些父类，实现了哪些接口等​ 字段表集合：“字段”(Field)包括类级变量以及实例级变量 方法表集合： 属性表集合：</description></item><item><title>4. 类加载机制</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/d-64f7ab1c4a97853c/n-7c32249aea3b528f/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/d-64f7ab1c4a97853c/n-7c32249aea3b528f/</guid><description>在Java程序中，对于任意一个类，都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性。如果一个类被两个不同的加载器加载，即使来源是同一个Class文件，那这也是两个不同的类，主要会体现在，Class对象的equals()方法，isInstance()方法的返回结果，以及使用instance-of关键字做对象所属关系判定等各种情况。## 1. 类的生命周期 1. 加载 # 通过一个类的全限定名来获取定义此类的二进制字节流。​
将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。​
在内存中生成一个代表这个类的java.lang.Class对象，作为方法区这个类的各种数据的访问入口。
2. 验证 # 文件格式验证：例如是否以魔数0xCAFEBABE开头；版本号等能否被虚拟机执行。​ 元数据验证：进行语义分析，确保符合Java语言规范。例如这个类不是抽象类,是否实现了其父类或接口之中要求实现的所有方法.​ 字节码验证：通过数据流和控制流分析，确定程序语义是合法的、符合逻辑的。​ 符号引用验证：符号引用验证可以看作是对类自身以外(常量池中的各种符号引用)的各类信息进行匹配性校验 例如：根据符号引用描述的名字能否找到对应的类；或者符号引用中的类、字段、方法的可访问性(private、protected、public、&amp;lt;package&amp;gt;)是否可被当前类访问等。 3. 准备 # 准备阶段主要是为类的静态变量（Static变量）分配内存，并将其初始化为默认值（0，0L，null，false等这种）。
4. 解析 # 解析阶段是Java虚拟机将常量池内的符号引用替换为直接引用的过程。包括（类或接口解析；字段解析；方法解析；接口方法解析）​
符号引用（Symbolic Reference）：写在 Class 文件里的&amp;quot;字面量&amp;quot;描述，它不关心内存地址，只描述&amp;quot;我要找谁&amp;quot;（比如类的全限定名、方法名和描述符）。 直接引用（Direct Reference）：符号引用在被解析（Resolve）后，指向内存中的实际地址（比如方法区中的内存偏移量、句柄或指针），JVM 拿着它就能直接找到目标。
5. 初始化 # 初始化是为类的静态变量赋予正确的初始值（前面准备阶段是为变量赋零值），JVM负责对类进行初始化，主要对类变量进行初始化。
2. 类加载器和类加载机制 # 在Java程序中，对于任意一个类，都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性。如果一个类被两个不同的加载器加载，即使来源是同一个Class文件，那这也是两个不同的类，主要会体现在，Class对象的equals()方法，isInstance()方法的返回结果，以及使用instance-of关键字做对象所属关系判定等各种情况。
三层类加载器
启动类加载器：负责加载存放在 &amp;lt;JAVA_HOME&amp;gt;\lib目录，或者被-Xbootclasspath参数所指定的路径中存放的，而且是Java虚拟机能够识别的类库加载到虚拟机的内存中。​
扩展类加载器：这个类加载器是在类sun.misc.Launcher$ExtClassLoader 中以Java代码的形式实现的。它负责加载&amp;lt;JAVA_HOM E&amp;gt;\lib\ext目录中，或者被java.ext.dirs系统变量所 指定的路径中所有的类库​
应用程序类加载器：由于应用程序类加载器是ClassLoader类中的getSystemClassLoader()方法的返回值，所以有些场合中也称它为“系统类加载器”。它负责加载用户类路径 (ClassPath)上所有的类库。
双亲委派模型 # 当一个类加载器收到&amp;quot;加载某个类&amp;quot;的请求时，它不会自己立刻去加载，而是：
先把这个请求委派给父类加载器去完成。 如果父类加载器加载成功，就直接返回结果。 只有父类加载器加载失败（找不到这个类）时，子加载器才会自己尝试加载。</description></item></channel></rss>