JVM

浏览该分类下的所有文章

从96%到70%

本文记录了把四个独立的 Spring Boot 项目(chat、puke、zepp、blog)合并为一个 Maven 多模块工程,只启动一个 total‑app.jar 的实践。原先每个项目占用一个 JVM,导致服务器内存接近 96%;通过在根 pom 统一依赖、在 launcher 中用 SpringApplicationBuilder 依次启动四个 ApplicationContext,并将配置分别放在 chat.yml、puke.yml、zepp.yml、blog.yml 中,消除了 JVM 底座的重复开销,内存降至约 70%。文章重点阐述了类路径冲突、资源目录重名、自动配置串扰和日志全局化等踩坑及对应的统一依赖、资源隔离、spring.autoconfigure.exclude 等解决方案。部署时仅需一次打包并用单条 java 命令启动,端口和 Nginx 配置保持不变,运维更简洁。该方案适合资源受限、访问量不高且对隔离要求不强的场景,虽牺牲了故障隔离,但能显著降低内存压力,为小型服务器提供务实的优化路径。

一次OOM排查实录

日志在运行时被硬截断,排查后发现是 Linux OOM Killer 将进程强制 kill,根因是 2 GB 服务器同时运行 3 个未限制堆大小的 Spring Boot 项目、MySQL 8.0 和监控组件,JVM 默认占用近 3 GB,MySQL 参数又消耗数百 MB,且没有 Swap 作为缓冲。通过为每个 JVM 设置‑Xms/‑Xmx(如 512 M、256 M),调小 MySQL 的 innodb_buffer_pool、max_connections、关闭 performance_schema 并添加 2 GB swap,内存使用降至安全范围,进程不再被 OOM Killer 杀死。经验教训是:小内存机器必须限制 JVM、精简 MySQL 配置并配置 swap,长期方案是迁移数据库或升级机器。

JVM对象创建与内存分配机制

JVM在执行new指令时首先检查类是否已加载、解析、初始化,然后在堆中为对象分配内存,采用“指针碰撞”或“空闲列表”方式,并通过CAS或TLAB解决并发冲突。分配后进行零值填充,设置对象头(包含hash、年龄、锁状态、类指针等),最后执行构造函数完成属性赋值。对象大小受对象头、实例字段和8字节对齐填充影响,默认开启指针压缩(UseCompressedOops/UseCompressedClassPointers)以降低内存占用并支持最高32 GB堆。JVM通过逃逸分析和标量替换可将不逃逸对象分配到栈上,减轻GC压力。

JVM类加载机制

JVM在执行 main 方法时先通过类加载器把主类加载到方法区,加载过程依次为加载、验证、准备、解析、初始化。加载阶段在内存生成对应的 Class 对象;验证检查字节码合法性;准备为静态字段分配默认值;解析把符号引用转为直接引用;初始化执行静态代码块并赋予真实值。JVM 提供引导、扩展、应用和自定义四种加载器,启动时由 Launcher 创建 ExtClassLoader 与 AppClassLoader。类加载遵循双亲委派机制:先交给父加载器(最终到引导加载器)尝试加载,若失败再由当前加载器自行查找。示例代码展示了按需加载、静态块打印以及各加载器的加载路径,说明了类加载的延迟性和层次结构。

深入理解Java虚拟机(JVM):内存模型与垃圾回收机制

本文系统阐述了JVM的内存结构与垃圾回收机制。首先介绍了程序计数器、虚拟机栈、本地方法栈、Java堆和方法区五大内存区域及其作用;随后解析了四类GC算法——标记‑清除、复制、标记‑整理和分代收集,并给出GC调优要点,包括选择合适的收集器、合理配置堆大小、优化对象分配以及使用VisualVM、JConsole等工具监控分析。掌握这些内容有助于提升代码性能、避免内存泄漏,并在面试中展示技术深度。

Java面试必会知识点

抱歉,我无法直接访问该链接中的内容。请您把文章的正文粘贴在这里,我会根据提供的文本为您生成符合要求的摘要。

面试现场【JVM篇】

本文系统梳理了 JVM 面试常见要点,包括运行时内存结构(程序计数器、虚拟机栈、本地方法栈、堆、方法区、直接内存),垃圾回收原理(引用计数、根可达、GC Roots 分类),四种引用类型,分代收集假设与记忆集,标记‑清除、复制、整理三大算法及 STW、Safe‑point、OopMap 的作用。随后简介了 Serial、ParNew、Parallel Scavenge、Parallel Old、CMS、G1 等主流收集器的特点与适用场景,并简述对象栈上分配、内存布局、类加载双亲委派等概念,为面试提供完整参考。

面试现场【综合篇】

本篇面试指南围绕系统设计与实现展开,涵盖项目亮点、零拷贝原理、五大IO模型及NIO与多路复用区别、Future阻塞获取结果机制、ReentrantLock 与 synchronized 的实现与差异、AQS、乐观/悲观锁、Paxos 协议、B+树特性、TCP 拥塞控制、JVM 实践、数据库分库分表及其缺点、分布式事务(TCC)方案、RocketMQ 消息可靠性保证,以及常见算法题。通过概念阐释与实现细节,帮助读者系统复习面试热点。

JVM之RTTI与反射

RTTI(运行时类型识别)通过获取 Class 对象来在运行时获取已知类的完整信息,获取方式包括 Class.forName、.class 和对象的 getClass(),前者会立即初始化类,后者在首次使用静态成员时才初始化。反射则用于编译时未知的类:在运行时加载对应的 .class 文件后,可通过 Class 的 getMethods、getConstructors 等获取 Method、Constructor 对象并实例化对象。核心区别在于 RTTI 需要编译期已知类名并在编译时检查 .class,而反射在运行时才打开并检查 .class,实现对未知类型的动态操作。

JVM垃圾收集器ParNew&CMS与底层三色标记算法

文章介绍了JVM分代回收的基本原理,阐述了新生代采用复制算法、老年代使用标记‑清除或标记‑整理的原因,并详细比较了Serial、Parallel、ParNew、CMS等收集器的实现与适用场景。重点解析了CMS的四阶段并发标记、三色标记、写屏障及其产生的浮动垃圾、漏标问题,提供了ParNew+CMS在大流量电商系统中的参数调优方案,强调通过合理设置堆、Survivor、晋升阈值等可降低Full GC频率,提高响应时延。

JVM垃圾收集器汇总

Serial 是单线程复制收集器,适用于 Client 模式小堆,停顿可接受;ParNew 为其多线程版,可配合 CMS 使用,在 Server 环境多 CPU 时提升并行度。Parallel Scavenge 同样是多线程复制收集器,侧重吞吐量,通过‑XX:GCTimeRatio、‑XX:MaxGCPauseMillis 调节;对应的老年代有 Serial Old(单线程标记‑整理)和 Parallel Old(多线程标记‑整理),后者与 Parallel Scavenge 组合实现高吞吐。CMS 采用并发标记‑清除,目标最短停顿,但对 CPU 敏感、产生碎片且无法处理浮动垃圾。G1 采用分区‑并行‑增量回收,提供可预测的停顿时间,调参主要是‑XX:MaxGCPauseMillis 等。整体上,JVM 提供了从单线程到并行、从低停顿到高吞吐的多种收集器,以满足不同应用场景的性能需求。

JVM垃圾收集器G1&ZGC

G1(-XX:+UseG1GC)将堆划分为约2048个等大小Region,保留但不强制分代,采用复制算法在STW阶段按“回收价值‑成本”优先选择Region,实现可预测的停顿(‑XX:MaxGCPauseMillis),并通过Humongous区专门处理大对象。G1的主要GC类型为Young、Mixed和Full,提供丰富的调优参数以平衡吞吐量和延迟,适合8 GB 以上、停顿要求在 0.5 s 以内的大内存服务器。 ZGC(-XX:+UseZGC)是 JDK 11 引入的低延迟收集器,目标是堆大小任意(TB 级)时仍保持 ≤10 ms 停顿,采用单代、Region(小‑2 MB、 中‑32 MB、 大‑≥4 MB)布局,利用读屏障、颜色指针和自愈转发表实现全并发标记‑整理,并自动感知 NUMA。ZGC 牺牲约 15% 吞吐以换取极短、可预测的停顿,适用于对延迟极为敏感的超大堆应用。