0%

JVM 生命周期:从启动到退出的完整历程

JVM(Java 虚拟机)作为运行字节码的虚拟进程,其生命周期遵循 “启动 - 执行 - 退出” 的完整流程。理解这一过程有助于深入掌握 JVM 的运行机制,以及排查与进程生命周期相关的问题(如进程异常退出、资源未释放等)。

JVM 启动:初始化与类加载

JVM 的启动是一个从无到有创建虚拟机进程的过程,核心是通过引导类加载器加载初始类,完成虚拟机的初始化。

1. 启动触发方式

  • 命令行启动:通过java命令启动(如java -jar app.jarjava com.example.Main),底层调用 JVM 的启动接口(如JNI_CreateJavaVM)。
  • 嵌入式启动:通过 JNI(Java Native Interface)在其他语言(如 C/C++)中嵌入 JVM,手动调用启动接口创建虚拟机实例。

2. 启动核心步骤

  1. 创建 JVM 实例:操作系统分配进程资源,初始化 JVM 的内部数据结构(如内存管理模块、线程管理模块)。
  2. 初始化引导类加载器:引导类加载器(Bootstrap ClassLoader)是 JVM 自带的加载器,负责加载 JVM 运行必需的核心类(如java.lang.Objectjava.lang.ClassLoader等,位于rt.jar中)。
  3. 加载初始类
    初始类由虚拟机实现指定(通常是用户程序的入口类,即包含main方法的类)。引导类加载器通过类的全限定名找到并加载该类,触发类加载的 “加载 - 链接 - 初始化” 流程(见前文)。
  4. 启动主线程:初始化完成后,JVM 创建主线程(main线程),执行初始类的main方法,标志着程序开始执行。

3. 启动阶段的关键特点

  • 启动过程依赖 JVM 的配置参数(如堆大小-Xms、垃圾回收器-XX:+UseG1GC等),这些参数会影响内存分配、执行引擎等核心组件的初始化。
  • 若初始类加载失败(如类不存在、字节码损坏),JVM 会在启动阶段抛出错误并终止。
阅读全文 »

Git 修改提交信息:从最新提交到历史提交的完整指南

在使用 Git 时,提交信息(commit message)是版本历史的重要说明,偶尔会出现拼写错误、信息不全等问题。无论是修改最近一次提交,还是调整历史提交记录,Git 都提供了相应的工具。本文将详细介绍不同场景下修改提交信息的方法。

修改最新一次提交信息(简单场景)

如果刚提交完就发现信息有误,直接使用 git commit --amend 即可快速修改,这是最常用的场景。

操作步骤:

  1. 执行修改命令

    1
    git commit --amend

    执行后会打开默认编辑器(如 Vim),显示当前最新提交的信息。

  2. 编辑提交信息

    • 在编辑器中修改错误内容(如将 “fix: 修 bug” 改为 “fix: 修复登录页面验证码失效问题”)。
    • 保存并退出编辑器(Vim 中按 Esc 后输入 :wq)。
  3. 完成修改
    修改后,Git 会生成一个新的 commit ID,覆盖原有的最新提交(旧提交会被自动清理)。

简化命令:

如果只需修改提交信息,无需修改提交内容,可直接在命令行指定新信息:

1
git commit --amend -m "新的提交信息"
阅读全文 »

Linux 中的 file 对象:进程视角下的已打开文件

在 Linux 系统中,file 对象(文件对象)是进程与文件交互的核心接口,代表进程已打开的文件实例。它与 inode、dentry 共同构成了文件操作的底层框架,但 file 对象更贴近进程的操作视角,记录了进程访问文件的动态状态。

file 对象的本质与核心作用

什么是 file 对象?

file 对象是 Linux 内核在内存中创建的一种数据结构,由 open() 系统调用生成,随 close() 系统调用销毁。它仅存在于进程的上下文中,代表进程对某个文件的 “打开实例”,记录了该进程访问文件的具体方式和状态。

核心功能

  • 跟踪进程对文件的当前偏移量(读写位置);
  • 记录文件的打开模式(如只读 O_RDONLY、读写 O_RDWR、追加 O_APPEND 等);
  • 关联文件的底层元数据(通过指向 dentry 和 inode,间接关联文件的物理信息);
  • 实现文件描述符(fd)与实际文件的映射(进程通过 fd 操作 file 对象)。

file 对象与其他文件系统对象的关系

file 对象、dentry(目录项)、inode(索引节点)是 VFS(虚拟文件系统)的三大核心对象,三者的关系如下:

对象类型 本质 核心关联 唯一性特征
file 进程打开的文件实例 通过 f_path.dentry 指向 dentry 同一文件可被多个进程打开,对应多个 file 对象
dentry 文件名与 inode 的映射 通过 d_inode 指向 inode 同一文件的硬链接对应多个 dentry,但指向同一 inode
inode 文件的物理元数据 记录文件权限、数据块指针等 唯一标识一个文件(跨进程)

形象比喻

  • inode 是文件的 “身份证”(唯一标识物理文件);
  • dentry 是文件的 “户口本”(记录文件名及家庭关系);
  • file 对象是进程的 “借阅证”(记录某进程如何使用该文件)。

file 对象的核心属性

file 对象包含多个关键成员,决定了进程与文件的交互方式,主要包括:

阅读全文 »

JVM(Java 虚拟机)全面解析:从原理到结构

JVM(Java Virtual Machine,Java 虚拟机)是 Java 生态的核心,它不仅是 Java 语言的运行环境,还支持 Scala、Kotlin、Groovy 等多种基于 JVM 的语言,被誉为 “最好的虚拟机”。其设计理念实现了 “一次编译,到处运行” 的跨平台特性,同时提供自动内存管理和垃圾回收等核心功能,极大简化了开发者的工作。

JVM 的核心定位与特性

作为多语言运行平台

JVM 的本质是二进制字节码的运行环境,它不直接依赖于 Java 语言,而是依赖于符合 JVM 规范的字节码(.class 文件)。任何能编译为 JVM 字节码的语言(如 Scala、Kotlin)都能在 JVM 上运行,这使得 JVM 成为跨语言的统一执行平台。

核心特性

  • 一次编译,到处运行
    Java 源码经编译生成字节码(.class),JVM 负责将字节码解释 / 编译为对应平台的机器指令,实现跨操作系统(Windows、Linux、macOS 等)和硬件架构的运行。
  • 自动内存管理
    开发者无需手动分配和释放内存,JVM 通过内存模型(如堆、栈的划分)自动管理内存分配,减少内存泄漏风险。
  • 自动垃圾回收(GC)
    JVM 内置垃圾回收器,自动识别并回收不再使用的对象内存,避免内存溢出(OOM)问题(需合理配置 GC 策略)。

编译器与解释器:JVM 的执行方式

JVM 的执行效率与其采用的 “解释 + 编译” 混合模式密切相关。理解编译器与解释器的区别,是掌握 JVM 执行原理的基础。

阅读全文 »

Spring Bean 作用域(Scope)全解析:从单例到 Web 专用作用域

Spring Bean 的作用域(Scope) 定义了 Bean 在 Spring 容器中的生命周期范围与实例创建规则,直接影响 Bean 的复用性、线程安全性和资源占用。Spring 提供 5 种核心作用域,涵盖普通 Java 应用(单例 / 原型)和 Web 应用(请求 / 会话 / 应用级),本文将详细拆解每种作用域的特性、适用场景、底层实现及注意事项。

Spring Bean 作用域总览

Spring 容器中 Bean 的 5 种作用域,按适用场景可分为普通应用作用域(适用于所有环境)和Web 专用作用域(仅适用于 Spring Web 环境,如 Spring MVC):

作用域名称 英文标识 核心特性 适用场景 生效环境
单例 singleton 容器中仅存在1 个实例,随容器启动创建(默认懒加载可配置),全局共享 无状态组件(如 Service、Dao、工具类) 所有环境(默认)
原型 prototype 每次调用 getBean() 或注入时创建新实例,容器不管理销毁 有状态组件(如 Command 对象、请求参数封装类) 所有环境
请求 request 每个 HTTP 请求对应1 个实例,请求结束后销毁 存储请求级数据(如当前请求的用户信息) Web 环境(Spring Web)
会话 session 每个 HTTP Session 对应1 个实例,会话过期后销毁 存储会话级数据(如用户登录状态、购物车) Web 环境(Spring Web)
应用 / 全局会话 application 整个 ServletContext 对应1 个实例,与应用生命周期一致 存储应用级全局数据(如系统配置、字典缓存) Web 环境(Spring Web)
阅读全文 »