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]
【MFiX后处理】MFiX中使用des_usr_var输出颗粒的传热量(2020-11-27更新变更输出变量名方法) 参考之前Yin的那一篇博客 https://www.cnblogs.com/Jay-CFD/p/10621274.html 输出一下颗粒传热量 使用的算例是fluid_bed_dem_2d 打开des scalar tracking 前面都和Yin那篇一样,打开enable user scalar tracking 输入2 因为第一个用来测试Y加速度了 第二个输出传热量 然后在output vtk中勾选好 更改源代码 源代码为des_thermo_newvalues.f 在mfix-GUI自带的ed 阅读详情

相关推荐

Unity调用手机摄像头避坑指南:从权限检测到自动对焦问题解决

本文深入解析了Unity移动端集成手机摄像头时遇到的权限、对焦与性能等核心难题。针对权限管理,提供了健壮的原生接口调用方案;针对自动对焦模糊问题,详细对比了原生插件与第三方插件两种解决路径;并分享了分辨率选择、数据处理及功耗控制等关键性能优化技巧,帮助开发者构建稳定高效的摄像头功能。

weixin_29007243的博客 472

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

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

crg18438610577的博客 777

eQTL:连接突变与基因表达的桥梁

欢迎关注”生信修炼手册”!在高等生物中,很多的重要性状都为数量形状,比如农作物的产量,人类复杂疾病(高血液,糖尿病)等等。对于这些数量性状而言,往往受到多个基因的调控作用。为了更好的开展...

庐州月光的博客 7070

JVM虚拟机原理及JVM调优

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

治愈系的博客 534

ChatBI告别“NL2SQL依赖症”!从准确率50%到90%,3大技术路线+4个企业案例拆解核心玩法

摘要: ChatBI通过自然语言交互实现数据民主化,其核心是“语义理解+数据执行+知识沉淀”的全链路能力,而非单一的NL2SQL技术。行业采用三大技术路线提升准确率:专有知识库(提升30%)、指标标签语义层(准确率85%)、JSON中间层(多轮对话提升25%)。数据执行方案包括NL2SQL、NL2API等,需结合场景选择。企业落地需解决四大痛点:跨表查询准确率低(引入拓扑图)、模糊查询(用户干预机制)、响应慢(预计算缓存)、多轮对话(上下文池)。Spring AI Alibaba提供轻量级集成方案,助力企业

weixin_52610848的博客 1656

IGV实战指南:从数据导入到Peak可视化的全流程解析

本文提供了一份IGV实战指南,详细解析了从数据导入到Peak可视化的全流程。内容包括软件安装、参考基因组加载、测序数据处理、信号调整以及如何精准定位和可视化Peak区域,并分享了导出出版级矢量图的高级技巧,帮助用户高效完成基因组数据可视化分析。

weixin_29212867的博客 149

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

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

weixin_28745067的博客 649

AI 大模型接口太零散?自建私有模型管理平台统一整合,管理使用超方便!(支持飞牛nas、群晖nas等服务器快速部署)

面对多种 AI 大模型接口难统一、管理繁琐的问题🤯,本文分享一款超实用开源网关工具⚡,可聚合各大模型、自动转接口、支持可视化管理,Docker 一键部署,大幅降低开发与维护成本🚀

XiaoqiangClub的博客 266

VMware Workstation_虚拟机的…

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

拖延癌患者自愈小记 555

SAP Joule for Consultants 与 Joule for Developers 全面解读

SAP推出面向不同用户群体的Joule AI助手:开发者版(Joule for Developers)专注于编码提效,嵌入开发工具链辅助生成、重构和测试代码;顾问版(Joule for Consultants)聚焦业务场景,集成SAP云应用知识库,为咨询项目提供方案设计、差距分析和实施指引。两者共享AI底座但功能侧重点不同:开发者版优化技术开发流程,顾问版加速项目交付周期。典型应用场景包括制造业云转型方案制定和ABAP代码迁移,分别展示了两版本在业务决策支持和技术实施中的价值。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 545

MATLAB - 机械臂手眼标定(眼在手内) - 估计安装在机器人上的移动相机的姿态

执行手眼校准有助于操作配备末端执行器(简称 “手”)的机械臂,该末端执行器依赖于摄像头提供的视觉数据。一旦完成了眼在手外的校准,机械臂就能准确地移动到摄像头识别的特定像素位置。这种能力是执行精确拾放任务(如分类、堆垛和分拣)的基础,即使在摄像机的确切位置和方向未知的情况下也是如此。机器人-摄像机系统有两种构型:眼在手内和眼在手外。在眼在手内构型中,摄像头直接安装在机器人手臂的末端执行器上。相反,在眼在手的构型中,摄像头固定在一个静止的物体上,机器人手臂在其视野内。

机器人控制与仿真应用 3352

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

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

qq_42934452的博客 563

【ComfyUI专栏】ComfyUI 常用工作流下载与分享网址

首先我们来分享第一个网站,Openart 网站,这个网站同时也能提供比较多的其他类型。但是如果希望下载工作流,我们可以访问到如下的这个站点。作为ComfyUI的学习用户来说,我们通常需要借助他山之石来帮助我们快速成长,因此我们需要找到能够分享和下载的网址。,当前网站是综合性网站,在网站中可以下载各种不同的类型,其中工作流只是可以下载的非常小的部分。这个网站也可以浏览不同的工作流,这个工作流的地址和访问如下的站点。

技术与管理的平衡木- 7806

从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

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

AKKA介绍

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

hellozhxy的博客 3853

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

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

《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、付费专栏及课程。

余额充值