JVM的自愈能力

在IT行业,碰到问题的第一个反应通常是——“你重启过没”——而这样做可能会适得其反,本文要讲述的就是这样的一个场景。

接下来要介绍的这个应用,它不仅不需要重启,而且毫不夸张地说,它能够自我治愈:刚开始运行的时候它可能会碰到些挫折,但会渐入佳境。为了能实际地展示出它的自愈能力,我们尽可能简单地重现了这一场景,这个灵感还得归功于[url=http://www.javaspecialists.eu/archive/Issue174.html]五年前heinz Kabutz发表的一篇老文章[/url]:




package eu.plumbr.test;

public class HealMe {
private static final int SIZE = (int) (Runtime.getRuntime().maxMemory() * 0.6);

public static void main(String[] args) throws Exception {
for (int i = 0; i < 1000; i++) {
allocateMemory(i);
}
}

private static void allocateMemory(int i) {
try {
{
byte[] bytes = new byte[SIZE];
System.out.println(bytes.length);
}

byte[] moreBytes = new byte[SIZE];
System.out.println(moreBytes.length);

System.out.println("I allocated memory successfully " + i);

} catch (OutOfMemoryError e) {
System.out.println("I failed to allocate memory " + i);
}
}
}



上述代码会循环地分配两块内存。每次分配的内存都是堆中总内存的60%。由于在同一个方法内会不停地进行这个内存分配,因此你可能会认为这段代码会不断地抛出 java.lang.OutOfMemoryError: Java heap space异常,永远无法正常地执行完allocateMemory方法。

我们先来对源代码进行下静态分析,看看这种猜测是否恰当:

1. 乍看一下这段程序的话,这确实是无法成功执行的,因为要分配的内存已经超出了JVM的限制。
2. 但再仔细分析下的话我们会发现第一次分配是在一个块作用域内完成的,也就是说这个块中定义的变量仅对块内可见。这意味着这些内存在这个代码块执行完成后便可以回收掉了。这段代码一开始应该是可以成功执行的,只是当它再去尝试分配moreBytes的时候才会挂掉。
3. 如果再查看下编译后的class文件的话,你会看到如下的字节码:




private static void allocateMemory(int);
Code:
0: getstatic #3 // Field SIZE:I
3: newarray byte
5: astore_1
6: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
9: aload_1
10: arraylength
11: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
14: getstatic #3 // Field SIZE:I
17: newarray byte
19: astore_1
20: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
23: aload_1
24: arraylength
25: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
[*]--- cut for brevity ----




从中能够看出,第一个数组是在位置3~5处完成分配的,并存储到了序号为1的本地变量中。随后在位置17处,正要分配另一个数组。不过由于第一个数组仍被本地变量所引用着,因此第二次分配总会抛出OOM的异常而失败。字节码解释器不会允许GC去回收第一个数组,因为它仍然存在着一个强引用。

从静态代码分析中可看出,由于底层的两个约束,上述的代码是无法成功执行的,而在第一种情况下则是能够运行的。这三点分析里面哪个才是正确的呢?我们来实际运行下看看结果吧。结果表明,这些结论都是正确的。首先,应用程序的确无法分配内存。但是,经过一段时间之后(在我的Mac OS X上使用Java 8大概是出现在第255次迭代中),内存分配开始能够成功执行了:





java -Xmx2g eu.plumbr.test.HealMe
1145359564
I failed to allocate memory 0
1145359564
I failed to allocate memory 1

… cut for brevity ...

I failed to allocate memory 254
1145359564
I failed to allocate memory 255
1145359564
1145359564
I allocated memory successfully 256
1145359564
1145359564
I allocated memory successfully 257
1145359564
1145359564
Self-healing code is a reality! Skynet is near...




为了搞清楚究竟发生了什么,我们得思考一下,在程序运行期间发生了什么变化?显然,Just-In-Time编译开始介入了。如果你还记得的话,JIT编译是JVM的一个内建机制,它可以优化热点代码。JIT会监控运行的代码,如果发现了一个热点,它会将你的字节码转化成本地代码,同时会执行一些额外的优化,譬如方法内联以及无用代码擦除。

我们打开下面的命令行参数重启下程序,看看是否触发了JIT编译。



[*]XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation


这会生成一个日志文件,在我这里是一个hotspot_pid38139.log文件,38139是Java进程的PID。在该文件中可以找到这么一行:



<task_queued compile_id='94' method='HealMe allocateMemory (I)V' bytes='83' count='256' iicount='256' level='3' stamp='112.305' comment='tiered' hot_count='256'/>



这说明,在运行了256次allocateMemory()方法2之后,C1编译器决定将这个方法进行3级编译。看下[url=http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/104743074675/src/share/vm/runtime/advancedThresholdPolicy.hpp]这里[/url]可以了解下分层编译的各个级别以及不同的阈值。在前面的256次迭代中这段程序都是在解释模式下运行的,这里的字节码解释器就是一个简单堆栈机器,它无法提前预知某个变量后续是否会被用到,在这里对应的是变量bytes。但是JIT会一次性查看整个方法,因此它能推断出后面不会再用到bytes变量,可以对它进行GC。所以才会触发垃圾回收,因此我们的程序才能奇迹般地自愈。我只是希望本文的读者都不要在生产环境碰到调试这类问题的情况。不过如果你想让某人抓狂的话,倒是可以试试在生产环境中加下类似的代码。


原创文章转载请注明出处:[url=http://it.deepinmind.com/jvm/2014/12/15/self-healing-jvm.html]http://it.deepinmind.com[/url]

[url=https://plumbr.eu/blog/self-healing-jvm?utm_source=feedly&utm_reader=feedly&utm_medium=rss&utm_campaign=rss]英文原文链接[/url]
EM4095低频RFID曼彻斯特解码实战:从原理图到MCU代码实现 本文详细介绍了EM4095低频RFID读卡器的设计与实现,从芯片工作原理、天线设计到曼彻斯特解码算法。重点讲解了基于STM32的MCU代码实现,包括定时器捕获、数字滤波和错误处理,为开发125kHz RFID系统提供实用指南。 阅读详情

相关推荐

(篇八)C语言在母串删子串、输入位置截取子串

文章目录一、字符串二、删除指定的字符三、从母串中截取子串四、输入位置截取子串 本篇主要介绍C语言字符串中的相关操作,然后分析两个C语言实例——在母串中指定删除子串、在母串中截取子串 一、字符串 了解C 语言的都知道,C语言中没有字符串类型,所以C语言是用字符串常量、字符指针、字符数组来表示字符串。这些字符串都是以 NULL、’\0’或者ASCII==0来结尾。说白了就是一个个字符组成一串有序序列,...

Viewinfinitely的博客 1512

JVM原理之详解现代垃圾回收器 Shenandoah 和 ZGC

JVM原理之详解现代垃圾回收器 Shenandoah 和 ZGC

crg18438610577的博客 777

智能座舱音频系统集成与调试:从芯片选型到音质优化实战

在智能座舱域控制器架构中,音频系统已从简单的功放加扬声器演进为SoC、数字音频总线、外部DSP与多通道功放协同的复杂子系统。TDM总线的时隙分配、PDM麦克风阵列的信号完整性,以及AEC回声消除算法如何与硬件协同,直接决定多音区体验和语音交互的可靠性。工程实践中,音频调试的关键在于先理顺供电、接地、时钟与数据路由,再针对功放削波、采样率失配、TDM slot错位等典型问题进行系统性排查。从芯片选型到系统级指标验收,只有将音频链路视为整车电子电气架构的一个协同整体,才能真正实现从“响”到“好听”的跨越。本文结

weixin_30162121的博客 364

JVM虚拟机原理及JVM调优

JVM虚拟机 JVM运行流程 生成.class可执行 >>> 类装载子系统 >>> 运行时数据区(内存模型) >>> 字节码执行引擎 内存模型 栈 局部变量表 ​ 存放局部变量 操作数栈 ​ 存放临时的操作数区域 动态链接 方法出口 堆 ​ 开辟内存空间,创建对象 方法区 ​ 常量 + 静态变量 + 类信息 本地方法栈 ​ native修饰,底层C语言实现的 ​ 本地方法栈运行的区域**(例如:加减操作)** 程序计数器 ​ 最经典的示例:多线程挂

治愈系的博客 534

语义通信实战:跳过“比特”保“语义”,手把手构建轻量级图像压缩重建网络(基于PyTorch)

本文详细介绍了基于PyTorch的轻量级语义通信系统LICRnet的实现,专注于图像压缩重建中的语义信息保留。通过深度可分离卷积、可变窗口多尺度注意力等创新技术,显著降低计算量并提升性能,特别适用于无人机巡检、远程医疗等物联网场景。文章包含完整的代码实现、训练策略及部署优化方案。

weixin_27697385的博客 221

高数15种常见特殊曲线:星形线、心形线、摆线、对数螺线、双曲螺线、阿基米德螺线、伯努利双纽线、三叶玫瑰线、四叶玫瑰线、六叶玫瑰线、三次抛物线、半立方抛物线、箕舌线、蔓叶线、笛卡儿叶形线、概率曲线

4.1 对数螺线(等角螺线、生长螺线)三叶玫瑰线、四叶玫瑰线、六叶玫瑰线。​7.2 半立方抛物线(尼尔曲线)10.笛卡儿叶形线(茉莉花瓣曲线)常考选择题、填空题,大题也涉及。​4.2 双曲螺线(倒数螺线)11.阿基米德螺线(等速螺线)3.摆线(圆滚线、旋轮线)5.双纽线(伯努利双纽线)1.星形线(四尖瓣线)2.心形线(心脏线)..................

刘鑫磊 1万+

虚拟服务器系统修复,即时虚拟机恢复

采用即时虚拟机恢复技术,企业可以直接从备份文件本身运行该功能,从而立即将虚拟机还原至生产环境。这有助于企业缩短还原时间并更好地实现恢复时间目标 (RTO),因为我们无需将备份存储中的任何数据复制到生产存储中。相反,我们仅需直接从备份目标启动虚拟机,用户便可以即时访问其文件和应用程序。准备就绪之后,我们可以直接使用 VMware Storage vMotion或其他迁移技术将虚拟机实时迁移回生产...

weixin_28745067的博客 649

Agent 智能体学习指南:从入门到求职的完整路线

AI Agent 不是更长的 prompt,而是一类系统设计——模型在受控环境里观察状态、选择动作、调用工具、接收反馈。本文系统梳理 Agent 的 5 个核心概念、7 个关键模块(Goal/State/Context/Tools/Loop/Guardrails/Eval)、三条学习路线(工程落地/研究算法/求职作品)、框架选型策略(LangGraph/OpenAI Agents SDK/Pydantic AI 等场景推荐),以及可执行的 7 天最小项目计划(从概念到简历 bullet)。

program哲学 229

VMware Workstation_虚拟机的…

攻防场景需要模拟多个主机,由于创建多个虚拟机非常耗空间,采用虚拟机的克隆方法。     下面是快照和克隆的介绍以及两者对比:   多重快照:   快照的含义:对某一个特定文件系统在某一个特定时间内的一个具有只读属性的镜像。当你需要重复的返回到某一系统状态,又不想创建多个虚拟机的时候,就可以使用快照功能。其实,快照并不是VMware Workstation 5的新功能。早在VMware Works

拖延癌患者自愈小记 555

AI应用架构师进阶:智能控制系统架构的多Agent设计

本文将从“AI应用架构师”的视角,系统讲解智能控制系统中多Agent架构的设计方法。理解多Agent系统的核心特性与在智能控制场景中的优势;掌握多Agent架构的设计流程:从需求分析到角色划分、通信设计、决策实现;通过实战案例(智能家居控制场景),手把手带你落地一个多Agent智能控制系统;探讨进阶话题:动态Agent组织、安全性设计、与大语言模型(LLM)的融合等。在多Agent系统中,Agent(智能体)是具备自主决策能力的最小执行单元。

小程序开发 1086

vue2/3 - 详细实现内网使用离线百度地图功能,百度地图如何离线加载详细教程(内网部署及使用),在vue中无需网络离线使用百度地图相关功能,提供最新完整的瓦片资源下载及相关工具(示例代码,一键复制

vue,vue2,vue3,百度地图,离线使用百度地图,百度地图瓦片官方下载,vue内网使用百度地图离线无网络,断网情况下使用百度地图,vue离线百度地图教程,如何实现内网部署百度地图,无需联网离线使用,vue+ts实现离线百度地图 内网离线百度地图,如何在百度地图Vue项目中下载离线地图,百度离线地图加载不出来,百度地图离线使用不显示怎么办,怎么解决vue内网使用离线百度地图加载失败问题,vue实现离线地图+百度瓦片,vue引入百度离线地图,vue项目如何使用离线百度地图和自定义地图样式,百度离线地图的下

✅ 精选推荐文章 1万+

使用虚拟机备份软件恢复OpenStack虚拟机

1、进入虚拟机备份系统 2、选择【虚拟机保护】——【恢复】,新建恢复任务,选择选择虚拟化类型【OpenStack】,勾选需要恢复的备份点,点击【下一步】 3、 设置恢复目标宿主机,并按需配置恢复虚拟机的名称、状态、存储、网络,点击【下一步】。 统一配置虚拟机:恢复的时候可以统一配置虚拟机的存储、网络和开/关机状态,配置完成后,还可以单独修改某个虚拟机的配置 4、设置恢复方式,包括【时间策略】、【限速策略】、【高级策略】 时间策略:包括【立即恢复】与【按时间策略恢复】,按需选择恢复方式

qq_42934452的博客 563

大学生数学建模赛题解析及优秀论文-2021电工杯A题高铁牵引供电系统运行数据分析及等值建模(附Python代码)

我国是世界上电气化铁路运营里程最长、服役电力机车型号最多、运营最 繁忙的国家。截至 2020年底,我国铁路年消耗电量约800亿千瓦时,约占三峡 年总发电量的 80%。图1为高速铁路牵引供电系统示意图,主要包括牵引变电所、牵引网和动车 组。牵引变电所将 220kV三相电压转换为满足电力机车运行的27.5kV单相电压, 其核心元件是牵引变压器。牵引网由馈线、接触网、钢轨、回流线等组成,完成 对电力机车的送电任务。...

wenyusuran的专栏 3169

从jvm的自愈说起-设计JVM的疯子和写java程序的疯子

  http://it.deepinmind.com/jvm/2014/12/15/self-healing-jvm.html这里说了一个观点,叫做 JVM的自愈能力,就是说JVM在遇到问题时会自己发现问题解决问题,举例如下:     package eu.plumbr.test; public class HealMe { private static final int ...

windshome的博客 345

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

AKKA介绍

akka简介 一开始想接触到akka,是在看一些并发相关资料的时候,查了下akka的官方介绍,介绍如下:Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用,使构建高并发的分布式应用更加容易。 听到高并发和分布式这两个关键字就已经足够让人想去探索究竟是什么样的框架,当深入查看各种资料后,发现当前大数据领域火热的spark、flink底层的分布式计算和通信实现都是akka,是不是很意外。虽然它是由scala编写的,但也同时提供java api接口,所以使用j..

hellozhxy的博客 3853

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Akka

akka@(scala)基本介绍Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和 Scala 的 Actor 模型应用。 官方网站 (http://akka.io/)的介绍是: Akka is a toolkit and runtime for building highly concurrent, distributed, and fault tole

oblesslyy的专栏 794

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

《Java纵擎云霄从语言本质到高并发分布式系统的架构突围指南》

该洞察将晦涩的锁协议升维为一致性的数学本质:无论是线程间还是节点间的等待与获取,本质都是在无向图中寻找环路约束下的递归解。书中重构ConcurrentHashMap的哈希冲突链表策略时,提出双向链表原子化分裂法:当负载因子超过阈值时,利用CAS+CAS_PAIR组合操作实现零停顿的桶扩容,这实质是时间换空间的拓扑变形理论在并发系统中的首次工程化论证。解包内部类和Lambda的引用传递机制后发现,语言层面的闭包泄露实则是面向对象ACID原则的隔离维度在高并发场景的物理表现形式。

VYiwXWsb的博客 310

混沌工程实战:用ChaosBlade模拟线上故障的5个经典场景(附避坑指南)

本文通过ChaosBlade工具,实战演练了模拟网络延迟、进程终止、资源竞争、磁盘故障及JVM应用层异常这5个经典线上故障场景。文章提供了详细的避坑指南,强调在完善的监控与基线基础上进行可控实验,旨在主动发现系统脆弱点,提升分布式系统的韧性。

w3x4y的博客 165

Java并发编程实战高并发场景下的线程管理与性能优化

这篇文章通过结合理论、代码片段(部分关键逻辑)、架构图示、量化数据,以及原创的工程案例,构建了从基础原理到工程实践的完整知识体系,同时融入了一些不常见但有效的优化思路,确保内容的稀缺性与启发性。- 拒绝策略的隐蔽陷阱:当使用`CallerRunsPolicy`可能导致请求堆积,实际应通过预警机制在QPS达到阈值时动态扩容,配合降级策略。- 任务队列的节奏控制:优先级队列(`PriorityBlockingQueue`)在电商秒杀场景下实现VIP用户的优先处理,提升关键用户体验。

WQVqJmpT的博客 390

Apache Druid的介绍和0.22.1版本集群部署

目录1. Apache Druid的介绍2. 部署规划3. 安装要求4. 下载解压(bigdata001上)5. 修改配置(bigdata001上)5.1 Druid通用配置5.2 修改Data服务配置5.3 修改Query服务6. 分发Druid目录(bigdata001上)7. 启动(在所有服务器上)7.1 一台服务器,启动多个服务设置7.2 启动master服务7.3 启动data服务7.4 启动query服务8. 查看Druid控制台 1. Apache Druid的介绍 Apache Druid适

Bulut0907 2120

Open-AutoGLM性能优化秘籍:让Java服务响应速度提升5倍

掌握Open-AutoGLM性能调优技巧,显著提升Java服务响应速度。本文详解在高并发场景下,如何通过JVM参数优化、对象池复用与异步处理策略,实现Open-AutoGLM Java应用性能跃升5倍,系统稳定性与吞吐量同步增强,值得收藏。

FastProceed的博客 690

【Java数据安全防线】:构建高可靠恢复机制的6个关键技术点

掌握Java数据恢复实战技巧,构建高可靠数据安全防线。涵盖事务日志回放、备份策略设计、故障点还原等6大关键技术,适用于金融、电商等高并发场景,保障系统容灾与数据一致性。方法实用,值得收藏。

CompiWander的博客 1045

CAT在生产环境的最佳实践与性能调优

本文全面探讨了CAT监控系统在大规模生产环境中的最佳实践与性能优化策略。内容涵盖大规模集群下的性能优化、监控数据采样与聚合算法、告警规则配置与通知机制,以及运维监控体系。文章详细介绍了架构层面的分布式部署与负载均衡、数据传输与网络优化、存储与IO优化、内存管理与GC调优等关键技术,并提供了智能采样机制、多通道告警通知和故障自愈等实用解决方案。 ## 大规模集群下的性能优化策略 在大规模分布式

gitblog_00518的博客 354
上一篇: 切勿自作聪明,慎用双括号反模式
下一篇: 动态语言已死?
spidercoco
博客等级 码龄18年 47粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值