JVM 中“对象存活判定方法”全面解析

1. 前言

在 Java 开发过程中,我们常常听到“垃圾回收”(Garbage Collection, GC)这一术语。JVM 通过垃圾回收机制自动管理内存,极大地简化了程序员的内存控制负担。然而,GC 究竟是如何判断哪些对象该回收、哪些应保留的呢?这正是“对象存活判定”的关键所在。

对象存活判定方法的效率和准确性,直接关系到系统性能的高低。在内存紧张的场景中,一个不合理的回收策略可能导致频繁 GC,甚至导致 OutOfMemoryError(OOM)错误。

Java 语言自诞生之初就非常重视内存安全问题,JVM 也随着版本更新不断优化垃圾回收算法。目前主流的 Java 8 就采用了更加高效的“可达性分析法”替代传统的“引用计数法”,以规避引用循环等典型问题。

本系列文章将从基础原理入手,深入剖析 JVM 如何判断对象是否“还活着”,并配合图解与示例代码,帮助开发者更好地理解这一 GC 背后的核心机制。

阅读后你将收获:

  • JVM 内存模型与对象管理原理

  • 引用计数法与可达性分析法的差异与优劣

  • 如何用代码分析对象是否会被 GC 回收

  • 实用工具(MAT、JVisualVM)的分析技巧

让我们从最基础的问题开始——“对象存活判定”到底指的是什么?

2. 什么是对象存活判定?

对象存活判定(Object Liveness Detection)是指 JVM 在垃圾回收过程中判断某个对象是否仍“有用”的一套逻辑机制。只有当 JVM 确认一个对象“无用”时,才会将其内存空间释放。

那么,什么是“有用”或“无用”?这个标准并非由程序员显式指定,而是 JVM 通过一定的算法推导得出。

从 JVM 的角度来看:

  • “有用”的对象:程序仍然可以访问到该对象。

  • “无用”的对象:程序中不再有任何方式可以访问到该对象。

这就涉及到两个关键问题:

  1. 程序如何“访问”一个对象?

  2. JVM 如何判断“是否还能访问”?

为了解决这两个问题,JVM 提供了两种主要的判断方式:

  • 引用计数法(Reference Counting):为每个对象维护一个引用计数器。

  • 可达性分析法(Reachability Analysis):从一组被称为 GC Roots 的起点出发,遍历对象图。

这两种方法各有利弊,也体现了 JVM 垃圾回收策略的演进方向。

在接下来的章节中,我们将逐一剖析这两种算法的底层原理、适用场景与实现机制,并结合示意图和代码说明其工作方式。

3. 方法一:引用计数法

基本原理

引用计数法的核心思想非常直观:

每当有一个地方引用该对象,其引用计数就加 1; 每当有一个引用失效,其引用计数就减 1; 当引用计数为 0 时,说明该对象“无人引用”,可以回收。

这一机制类似于手动管理内存语言(如 C++ 的智能指针),但在 Java 中并未采用这种方式作为主流实现。

示意图

假设我们有以下引用关系:

A --> B --> C^     ||_____|
  • 对象 A 引用了 B,B 引用了 C,C 又回头引用了 B,构成循环引用。

  • 即便 A 被回收,B 与 C 相互引用,导致引用计数不为 0,从而无法释放。

这就是引用计数法的致命缺陷:无法处理对象之间的循环引用问题

示例代码

虽然 Java 官方并未公开支持引用计数 GC,但我们可以通过伪代码演示其原理:

class MyObject {int refCount = 0;void addReference() {refCount++;}void removeReference() {refCount--;if (refCount == 0) {// 回收对象内存System.out.println("对象可以被回收");}}
}

使用时:

MyObject obj = new MyObject();
obj.addReference(); // 引用 +1
obj.removeReference(); // 引用 -1,若为0则可回收

当然,实际 JVM 中并未使用这种方法来管理对象生命周期。

优缺点分析

优势劣势
算法实现简单,效率高无法处理循环引用
回收实时性好增加引用维护成本
易于实现跨语言互操作与现代 JVM 架构不兼容

因此,虽然引用计数法在一些脚本语言(如 Python)或 C++ 的智能指针中应用较多,但在 Java JVM 中并未成为主流方法。

下一节我们将介绍 JVM 真正使用的对象存活判定方式:可达性分析法(Reachability Analysis)

4. 方法二:可达性分析法

GC Roots 概念

可达性分析法(Reachability Analysis)是目前 Java 虚拟机中对象存活判定的主流算法。

该方法的核心思想是:通过从一组称为 "GC Roots" 的起始节点出发,沿着对象引用链向下搜索,如果某个对象从 GC Roots 出发可达,则说明该对象是“活着”的;否则就会被判定为“死亡”。

GC Roots 的起始节点通常包括:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象

  • 方法区中类静态属性引用的对象

  • 方法区中常量引用的对象

  • 本地方法栈中 JNI 引用的对象

我们将在后续的章节中深入介绍这些 GC Roots 的类型。

分析流程

整个分析过程可以类比成遍历一张“对象图”:

  1. 建立对象引用图(Object Graph) 所有对象通过引用连接形成有向图,图中的边代表引用关系。

  2. 标记可达对象 从 GC Roots 出发,标记所有可到达的对象,形成“可达集合”。

  3. 未被标记的对象即为不可达对象 这些不可达的对象被视为垃圾,等待 GC 清理。

注意:即使对象不可达,JVM 并不会立刻回收它。 如果该对象覆盖了 finalize() 方法,还会进入一次“F-Queue”队列,被 GC 再次确认其是否真的不可用。

图解说明

            [GC Roots]|-------------------------|           |           |Obj1        Obj2       Obj3|                       |Obj4                   Obj5Obj6 (无法从 GC Roots 到达)
  • Obj1~Obj5 均从 GC Roots 可达,为存活对象。

  • Obj6 无任何引用链连接至 GC Roots,被视为“死亡对象”。

示例代码演示

虽然 JVM 自动完成对象图的构建和遍历,我们无法直接干预,但可以通过示例展示“对象是否可达”的效果:

public class ReachabilityDemo {static class Node {String name;Node reference;Node(String name) {this.name = name;}@Overrideprotected void finalize() throws Throwable {System.out.println(name + " 被回收了");}}public static void main(String[] args) {Node a = new Node("A");Node b = new Node("B");Node c = new Node("C");a.reference = b;b.reference = c;a = null; // 去除对 A 的强引用b = null; // 去除对 B 的强引用c = null; // 去除对 C 的强引用System.gc(); // 显式请求 GCtry {Thread.sleep(1000); // 等待 GC 完成} catch (InterruptedException e) {e.printStackTrace();}}
}

输出示例:

C 被回收了
B 被回收了
A 被回收了

说明 A、B、C 都在不可达状态下被 GC 回收。

优势与 JVM 的支持

优点说明
能解决循环引用问题不依赖引用计数值,识别结构关系
更适合复杂对象图图遍历可适配大型堆场景
JVM 官方支持Java 8 及以后的所有主流 JVM 均基于该方法

下一节我们将具体介绍 GC Roots 中的各类节点来源,帮助大家更深入理解对象“可达”的起点到底是什么。

 

5. GC Roots 的类型

在上一节中我们提到,GC Roots 是可达性分析的起点。那么,GC Roots 到底是什么?哪些对象或引用属于 GC Roots?理解 GC Roots 是掌握 JVM 垃圾回收机制的核心一步。

GC Roots 主要包括以下几种类型的引用:

1. 虚拟机栈中的引用(局部变量表)

每个线程在执行方法时都会创建一个栈帧(Stack Frame),其中的局部变量表中保存着各种基本类型和对象引用。

public class StackReferenceDemo {public static void main(String[] args) {Object obj = new Object(); // obj 是 GC Root 引用System.gc();}
}

在这个例子中,obj 是定义在主方法中的局部变量,它保存在栈帧的局部变量表中,因此是 GC Roots。

2. 方法区中类静态属性引用的对象

静态字段随着类的加载而存在于方法区中,引用的对象也会被视为 GC Roots。

public class StaticReferenceDemo {private static Object staticObj = new Object(); // 属于 GC Rootpublic static void main(String[] args) {System.gc();}
}

即使没有局部变量引用 staticObj,它依然不会被 GC,因为它是类的静态属性。

3. 方法区中常量引用的对象

常量池中的引用,如字符串常量等,也是 GC Roots 的一部分。

public class ConstantPoolDemo {public static void main(String[] args) {String str = "hello world"; // 字符串常量常驻内存System.gc();}
}

在这个例子中,字符串 "hello world" 常驻在运行时常量池中,是 GC Roots 的一部分,不会被回收。

4. 本地方法栈中的 JNI 引用(Native 引用)

如果 Java 程序调用了本地方法(如 C/C++ 实现的库),这些 native 方法中持有的对象引用也会被当作 GC Roots。

public class JNIDemo {static {System.loadLibrary("native-lib");}public native void callNative();
}

虽然无法用 Java 展示 native 层引用的具体内容,但这些引用 JVM 会在 GC 时特殊处理。

5. 活跃线程

所有运行中的线程(如主线程、GC线程、后台线程等)都是 GC Roots,因为它们自身的引用链天然“存活”。只有当线程执行结束、退出后,它们才会从 GC Roots 移除。

6. JVM 内部保留的系统类加载器

例如 sun.misc.Launcher$AppClassLoaderExtClassLoader 等,这些类加载器加载的类及其引用的对象会被视为 GC Roots。

7. JDK 特殊结构

System.in/out/err、线程上下文类加载器、反射中的 Method/Field/Constructor 对象、线程组等。这些结构大多存在于系统级类中,使用时容易导致内存泄露。

总结 GC Roots 类型

GC Roots 类型是否常见是否手动可控
虚拟机栈引用✅ 常见✅ 可控
静态属性引用✅ 常见✅ 可控
常量池引用✅ 常见❌ 不建议操作
JNI 本地引用❗ 复杂❌ 不建议操作
活跃线程引用✅ 常见❌ 不可控
类加载器引用✅ 常见❌ 不可控
系统类结构引用✅ 隐蔽❌ 不可控

理解 GC Roots 的种类不仅有助于判断哪些对象能被 GC 回收,也对分析内存泄露、优化引用管理非常有帮助。

在下一节中,我们将进一步探索 Java 中的 finalize() 机制,以及对象“抢救”自己的最后机会。

6. Finalize 机制与固定对象

即使一个对象在 GC Roots 的可达性分析中被判定为“不可达”,也不代表它立刻会被回收。Java 提供了一个“临终遗言”机制,即 finalize() 方法,使对象有一次自我拯救的机会。

6.1 什么是 finalize()

finalize()java.lang.Object 类中的一个方法:

protected void finalize() throws Throwable {// 释放资源或对象复活的钩子方法
}

当对象第一次被判定为不可达时,GC 会检查该对象是否覆盖了 finalize() 方法,且该方法是否尚未被调用。如果满足条件,JVM 会将该对象放入一个名为 Finalization Queue 的队列中,由一个低优先级的 Finalizer 线程去执行其 finalize() 方法。

注意:每个对象的 finalize() 方法最多只会被调用一次。

6.2 finalize() 能做什么?

  • 释放资源:用于释放文件句柄、关闭网络连接等非内存资源(但不推荐这么用,推荐使用 try-with-resources)。

  • 复活对象:对象在 finalize() 中如果再次赋值给 GC Roots 引用链中的某个变量,则对象会“复活”。

6.3 示例:对象的自我拯救

public class FinalizeRescueDemo {public static FinalizeRescueDemo OBJ = null;@Overrideprotected void finalize() throws Throwable {super.finalize();System.out.println("finalize() 方法被调用");OBJ = this; // 对象复活!}public static void main(String[] args) throws InterruptedException {OBJ = new FinalizeRescueDemo();// 第一次 GC,对象有机会复活OBJ = null;System.gc();Thread.sleep(1000);System.out.println(OBJ != null ? "对象存活" : "对象死亡");// 第二次 GC,finalize() 不会再被调用OBJ = null;System.gc();Thread.sleep(1000);System.out.println(OBJ != null ? "对象存活" : "对象死亡");}
}

运行结果:

finalize() 方法被调用
对象存活
对象死亡

说明:第一次 GC 时 finalize() 被调用,OBJ 被重新引用,从而复活。第二次 GC 时不再执行 finalize(),对象被真正回收。

6.4 finalize() 的问题与风险

  • 不可控时机:执行时间不确定,依赖 GC。

  • 影响性能:JVM 要维护一个队列和额外线程。

  • 风险隐患:对象复活逻辑可能导致资源泄露或更难以调试的 bug。

  • 已被废弃:Java 9 开始标注为 @Deprecated,建议使用 java.lang.ref.Cleaner 替代。

6.5 替代方案:Cleaner

import java.lang.ref.Cleaner;public class CleanerDemo {private static final Cleaner cleaner = Cleaner.create();static class Resource implements Runnable {@Overridepublic void run() {System.out.println("资源被清理");}}public static void main(String[] args) {Object obj = new Object();cleaner.register(obj, new Resource());}
}

Cleaner 提供了比 finalize() 更轻量、可控的资源清理方式,推荐在现代 Java 项目中使用。

7. 不同引用类型与垃圾回收行为

Java Reference类及其实现类深度解析:原理、源码与性能优化实践

Java 中定义了四种不同级别的引用类型:强引用(Strong Reference)软引用(Soft Reference)弱引用(Weak Reference)虚引用(Phantom Reference),它们在 JVM 中表现出不同的“生存权重”。理解这些引用类型对于资源缓存、内存优化和对象生命周期控制至关重要。

7.1 强引用(Strong Reference)

这是最常见的引用类型:

Object obj = new Object();

只要强引用还存在,GC 永远不会回收该对象。

特性

  • 是默认引用类型。

  • 会阻止 GC 回收所指向的对象。

示例

public class StrongReferenceDemo {public static void main(String[] args) {Object obj = new Object();System.gc();System.out.println(obj != null ? "对象未被回收" : "对象被回收");}
}

输出:对象未被回收

7.2 软引用(Soft Reference)

软引用是一种比较“温柔”的引用。它在内存不足时才会被 GC 回收。

SoftReference<Object> softRef = new SoftReference<>(new Object());

常用于内存敏感的缓存。

示例

import java.lang.ref.SoftReference;public class SoftReferenceDemo {public static void main(String[] args) {Object obj = new Object();SoftReference<Object> softRef = new SoftReference<>(obj);obj = null;System.gc();if (softRef.get() != null) {System.out.println("软引用对象仍存活");} else {System.out.println("软引用对象被回收");}}
}

注意:此示例中的回收依赖内存状况,可能不会立即触发。

7.3 弱引用(Weak Reference)

弱引用在 GC 时总是会被回收。

WeakReference<Object> weakRef = new WeakReference<>(new Object());

特性

  • 非常适合使用在 ThreadLocal、元数据缓存等短生命周期场景。

示例

import java.lang.ref.WeakReference;public class WeakReferenceDemo {public static void main(String[] args) {Object obj = new Object();WeakReference<Object> weakRef = new WeakReference<>(obj);obj = null;System.gc();if (weakRef.get() != null) {System.out.println("弱引用对象仍存活");} else {System.out.println("弱引用对象被回收");}}
}

输出:弱引用对象被回收

7.4 虚引用(Phantom Reference)

虚引用无法通过 get() 方法访问,被用于对象被回收时收到通知。

PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), referenceQueue);

特点

  • 永远不会阻止 GC。

  • 常与 ReferenceQueue 配合使用。

示例

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;public class PhantomReferenceDemo {public static void main(String[] args) {Object obj = new Object();ReferenceQueue<Object> queue = new ReferenceQueue<>();PhantomReference<Object> phantomRef = new PhantomReference<>(obj, queue);obj = null;System.gc();System.out.println("phantomRef.get(): " + phantomRef.get());System.out.println("是否进入 ReferenceQueue: " + (queue.poll() != null));}
}

输出:

phantomRef.get(): null
是否进入 ReferenceQueue: true

说明:虚引用不会返回实际对象,只用于跟踪对象是否已被 GC。

7.5 引用强度对比总结

引用类型是否影响 GC 回收典型用途是否可通过 get() 访问对象
强引用普通对象引用
软引用视内存情况而定内存敏感缓存
弱引用ThreadLocal、临时元数据
虚引用是(立即回收)清理前回调通知

 

8. 垃圾收集器与对象存活判定策略

Java 虚拟机中的垃圾收集器(GC)负责自动管理堆内存,及时回收不再使用的对象。不同的垃圾收集器采用不同的算法和策略来判断对象是否存活,从而决定是否回收。理解这些策略有助于优化程序性能和内存管理。

8.1 常见垃圾收集器简介

收集器名称特点适用场景
Serial GC(串行收集器)单线程执行,简单高效适合小内存或单核环境
Parallel GC(并行收集器)多线程并行,吞吐量优先多核服务器环境
CMS GC(并发标记清理)低停顿,标记与清理并发执行对响应时间敏感的应用
G1 GC(Garbage First)分区管理,低停顿,适合大堆大内存多核服务器

 

8.2 对象存活判定的核心机制

无论使用哪种收集器,对象的存活判定都基于“可达性分析”(Reachability Analysis):

  • 从 GC Roots(如线程栈、静态变量)开始,遍历所有引用链。

  • 能被引用链访问到的对象被认为是存活的,不回收。

  • 无法访问的对象则被标记为可回收。

8.3 不同收集器的对象判定流程

Serial 和 Parallel 收集器

  • 标记-清除(Mark-Sweep)或标记-复制(Mark-Copy)算法

  • 先暂停应用(Stop-The-World),从 GC Roots 开始标记存活对象。

  • 清除未标记对象或复制存活对象到新空间。

CMS 收集器

  • 采用多阶段并发标记:

    • 初始标记:暂停应用,标记直接可达对象。

    • 并发标记:应用线程运行时,标记间接可达对象。

    • 重新标记:短暂停止应用,完成标记遗漏部分。

    • 并发清理:清理不可达对象。

G1 收集器

  • 将堆划分成多个固定大小的区域(Region)。

  • 并发标记阶段识别每个区域的存活对象数量。

  • 优先回收存活对象少的 Region,减少停顿时间。

  • 支持混合回收:回收年轻代和部分老年代。

8.4 代码示例:指定收集器启动参数

# 使用 Serial GC
java -XX:+UseSerialGC -Xmx512m -Xms512m MyApp# 使用 CMS GC
java -XX:+UseConcMarkSweepGC -Xmx2g -Xms2g MyApp# 使用 G1 GC
java -XX:+UseG1GC -Xmx4g -Xms4g MyApp

使用 VisualVM 或 JVisualVM 可以观察不同收集器下堆内存对象的存活情况。

9. 总结与实践建议

本文全面解析了 JVM 中对象存活判定的核心机制及其应用,包括可达性分析、引用类型、Finalize机制、垃圾收集器对判定策略的影响等关键内容。

9.1 对象存活判定的核心是“可达性分析”

  • 通过从 GC Roots 出发遍历引用链,判断对象是否仍被程序访问。

  • 只有不可达对象才有回收资格,确保安全且高效的内存管理。

9.2 多种引用类型助力内存优化

  • 强引用、软引用、弱引用、虚引用各具特点,开发者可根据需求选择不同引用,灵活控制对象生命周期和内存回收时机。

  • 理解它们的差异,有助于避免内存泄漏和提升程序稳定性。

9.3 Finalize机制存在风险,应尽量避免

  • finalize() 方法虽可让对象“复活”,但执行时机不确定,且影响性能。

  • 推荐使用 java.lang.ref.Cleaner 替代,更加安全且高效。

9.4 不同垃圾收集器对对象存活判定实现有差异

  • 串行、并行、CMS 和 G1 GC 等采用各自的标记算法和阶段,平衡吞吐量与延迟。

  • 了解垃圾收集器特性,合理配置 GC 参数,对提升系统性能至关重要。

9.5 实践建议

  • 在开发中,优先确保对象引用链清晰,避免意外的强引用导致内存泄漏。

  • 结合软弱引用,设计缓存等场景,提高内存利用率。

  • 监控和调优垃圾收集器,配合性能分析工具,及时发现和解决内存相关问题。

  • 避免依赖 finalize(),转用 Cleaner 和显式资源管理。

  • 对于大型应用,考虑采用 G1 或者更先进的收集器,兼顾响应和吞吐。

通过深入理解对象存活判定方法,开发者能更精准地控制内存管理,写出高效、稳定的 Java 应用。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/88528.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/88528.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

苹果公司高ROE分析

公司通过增加负债提升净资产收益率&#xff08;ROE&#xff09;的核心机制在于财务杠杆效应和资本结构优化&#xff0c;以下从原理、操作路径、风险边界及苹果案例四维度展开分析&#xff1a;名称解释&#xff1a; ROIC(投入资本回报率)&#xff1a;ROICNOPATInvested Capital …

【Linux系统】进程概念

1. 进程概念1.1 进程的本质核心定义用户视角&#xff1a;程序的动态执行实例&#xff08;如同时运行多个Chrome窗口即多个进程&#xff09;。内核视角&#xff1a;资源分配的最小实体单位&#xff0c;独享CPU时间片、内存空间和文件资源。现代定义&#xff1a;进程 内核数据结…

从LLM到VLM:视觉语言模型的核心技术与Python实现

本教程的完整代码可以在GitHub上找到&#xff0c;如果你有任何问题或建议&#xff0c;欢迎交流讨论。 引言&#xff1a;为什么需要VLM&#xff1f; 当我们与ChatGPT对话时&#xff0c;它能够理解复杂的文字描述&#xff0c;生成流畅的回答。但如果我们给它一张图片&#xff0c…

老系统改造增加初始化,自动化数据源配置(tomcat+jsp+springmvc)

老系统改造增加初始化&#xff0c;自动化数据源配置一、前言二、改造描述1、环境说明2、实现步骤简要思考三、开始改造1、准备sql初始化文件2、启动时自动读取jdbc文件&#xff0c;创建数据源&#xff0c;如未配置&#xff0c;需要一个默认的临时数据源2.1去掉sping mvc原本配置…

卫星通信终端天线的5种对星模式之二:DVB跟踪

要实现稳定可靠的卫星通信&#xff0c;地面终端天线必须精准地对准远方的卫星。对星的过程是一个不断搜索、不断逼近的过程&#xff0c;其目标是让天线波束中心精确指向卫星&#xff0c;从而获得最大信号接收与发射效率。 卫星通信终端天线的对星技术是保障卫星通信链路稳定的…

重构下一代智能电池“神经中枢”:GCKontrol定义高性能BMS系统级设计标杆

概述BMS&#xff08;电池管理系统&#xff09;作为新能源汽车动力电池与整车的核心纽带&#xff0c;通过实时监控电压、电流、温度及SOC等参数&#xff0c;控制电池充放电过程&#xff0c;保障电池安全性与使用寿命。随着电动汽车智能化发展&#xff0c;对BMS的响应速度、精度和…

面试150 对称二叉树

思路 联想递归三部曲&#xff1a;传入参数、遍历方式、返回什么。本题联想到先序遍历的方式,需要遍历整颗二叉树,最后返回的是一个布尔值。然后我们需要传入的是左子树和左子树的节点,然后分别进行比较。 # Definition for a binary tree node. # class TreeNode: # def __…

多线程的区别和联系

进程和线程的区别和联系1.一个进程可以包含多个线程&#xff0c;不能够没有线程2.进程是系统资源分配的基本单位&#xff0c;线程是系统调度执行的基本单位3.同一个进程里的线程之间&#xff0c;共用同一份系统资源4.线程是当下实现并发编程的主流方式&#xff0c;通过多线程&a…

两个文件夹自动同步

两个文件夹自动同步&#xff0c;非常简单&#xff0c;利用一些工具就可以轻松做到&#xff0c;设置完源和目标文件夹&#xff0c;点击启动就马上可以两个文件夹自动同步&#xff0c;对于一些有文件同步、文件灾备需求的老登&#xff0c;用起来会非常顺手&#xff0c;比如PanguF…

虚拟商品交易维权指南:数字经济时代的消费者权益保护

首席数据官高鹏律师数字经济团队创作AI辅助在元宇宙、NFT、虚拟情绪产品等新兴领域蓬勃发展的今天&#xff0c;虚拟商品交易已成为数字经济的重要组成部分。从游戏皮肤、在线课程到数字藏品&#xff0c;消费者在享受虚拟商品便捷性的同时&#xff0c;也面临着诸多法律风险。作为…

mysql 一条语句的执行流程

文章目录一条查询语句的执行流程连接器管理连接权限校验分析器优化器采样统计优化器选错索引改正执行器查询缓存存储引擎一条update语句的执行流程redo logredo log buffer结构redo log日志类型写入时机配置innodb_flush_log_at_trx_commitbinlogredo log和binlog 对比配置两阶…

【视频观看系统】- 需求分析

&#x1f3af; 一、项目目标 构建一个功能完备的视频观看网站&#xff0c;用户可以上传、浏览、观看视频&#xff0c;并在观看过程中实时发送/接收弹幕。系统具备良好的性能、可扩展性与用户体验&#xff0c;未来可逐步扩展为多媒体平台。&#x1f464; 二、用户角色分析用户类…

模型驱动的架构MDA的案例

在一个企业资源规划&#xff08;ERP&#xff09;系统开发项目中&#xff0c;目标是为一家中型制造企业打造一套高效且可扩展的管理系统&#xff0c;涵盖订单处理、库存管理等多个业务模块。项目团队采用了 MDA 的设计思想进行开发。​首先是业务需求分析与计算独立模型&#xf…

第一次搭建数据库

本文详细介绍第一次搭建数据库安装和配置过程, 包括卸载旧版本、下载安装、配置服务、环境变量等等 第一步下载mysql 在下载之前需要检查电脑上有没有安装mysql, 如果有再安装, 80%就会有问题 检查方法: 电脑-右键找到管理-服务-在服务中找有没有mysql服务若有请先 1.停止服务 …

洛谷题解 | UVA1485 Permutation Counting

目录题目描述题目思路AC 代码题目描述 https://onlinejudge.org/external/14/p1485.pdf 题目思路 dp。 定义 dpi,jdp_{i,j}dpi,j​ 为前 iii 个数的排列中恰好有 jjj 个小于号的排列总数。 考虑将数字 iii 插入到前 i−1i-1i−1 个数的排列中不同的位置&#xff1a; 如果…

飞算科技:以原创技术赋能电商企业数字化转型

在电商行业从流量竞争迈向精细化运营的当下&#xff0c;技术能力已成为决定企业生存与发展的核心要素。然而&#xff0c;高并发场景下的系统稳定性、个性化推荐算法的迭代效率、营销活动的快速响应等挑战&#xff0c;让许多电商企业陷入“技术投入大、见效慢”的困境。作为国家…

人工智能自动化编程:传统软件开发vs AI驱动开发对比分析

人工智能自动化编程&#xff1a;传统软件开发vs AI驱动开发对比分析 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 总有一行代码&#xff0c;能点亮万千星辰。 &#x1f50d; 在技术的宇宙中&#xff0c;我愿做永不停歇的探索者。 ✨ 用代码丈量…

用java实现一个自定义基于logback的日志工具类

✅ 动态创建: 无需配置文件&#xff0c;通过代码动态创建logback日志对象 ✅ Class对象支持: 使用LogUtil.getLogger(MyClass.class)的方式获取日志 ✅ 日期格式文件: 自动生成info.%d{yyyy-MM-dd}.log格式的日志文件 ✅ 文件数量管理: 只保留最近3个文件&#xff0c;自动删除历…

面试现场:奇哥扮猪吃老虎,RocketMQ高级原理吊打面试官

“你了解RocketMQ的高级原理和源码吗&#xff1f;” 面试官推了推眼镜&#xff0c;嘴角带笑&#xff0c;眼神里透着一丝轻蔑。 奇哥笑而不语&#xff0c;开始表演。面试场景描写 公司位于高楼林立的CBD&#xff0c;电梯直达28楼。面试室宽敞明亮&#xff0c;空气中混着咖啡香与…

Django Nginx+uWSGI 安装配置指南

Django Nginx+uWSGI 安装配置指南 引言 Django 是一个高级的 Python Web 框架,用于快速开发和部署 Web 应用程序。Nginx 是一个高性能的 HTTP 和反向代理服务器,而 uWSGI 是一个 WSGI 服务器,用于处理 Python Web 应用。本文将详细介绍如何在您的服务器上安装和配置 Djang…