jvm7 jvm8_自我修复的JVM

jvm7 jvm8

修正自己以清除弱点并获得优势 这篇帖子是关于一个应用程序的示例,其中解决每个IT问题的第一个解决方案-“您是否尝试过将其关闭并重新打开”-可能适得其反,弊大于利。

我们不需要关闭电源,而是拥有可以自愈的应用程序:它在一开始就失败了,但过了一段时间便开始平稳运行。 为了举例说明这种应用的实际应用,我们以最简单的方式重新创建了该应用, 并从Heinz Kabutz的Java Newsletter已有5年历史的帖子中汲取了灵感 :

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堆空间错误,并且永远不会成功完成allocateMemory()方法。

因此,让我们从对源代码的静态分析开始,看看我们的期望是否正确:

  1. 从第一次快速检查起,此代码确实无法完成,因为我们尝试分配的内存超过了JVM可用的内存。
  2. 如果我们仔细观察,我们会注意到第一次分配发生在有作用域的块中,这意味着在此块中定义的变量仅对该块可见。 这表明在完成块后,这些字节应符合GC的条件。 因此,我们的代码实际上应该从一开始就可以正常运行,因为当它尝试分配moreBytes时 ,先前的分配字节应该是无效的。
  3. 如果现在查看已编译的类文件,将看到以下字节码:
private static void allocateMemory(int);Code:0: getstatic     #3                  // Field SIZE:I3: newarray       byte5: 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)V14: getstatic     #3                  // Field SIZE:I17: newarray       byte19: 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清理第一个数组,因为它仍然被严格引用。

我们的静态代码分析向我们表明,由于两个根本原因,所提供的代码不应成功运行,而在一种情况下,应该可以成功运行。 这三者中哪一个是正确的? 让我们实际运行它,自己看看。 事实证明,这两个结论都是正确的。 首先,应用程序无法分配内存。 但是一段时间后(在具有Java 8的Mac OS X上,它发生在迭代#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...

为了理解实际发生的事情,我们需要思考一下,程序执行期间会发生什么变化? 当然,显而易见的答案是可以进行即时编译。 您还记得吗,即时编译是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()方法之后,C1编译器决定将该方法排队以进行C1层3编译。 您可以在此处获得有关分层编译级别和不同阈值的更多信息。 因此,我们的前256次迭代是在解释模式下运行的,在该模式下,字节码解释器作为一个简单的堆栈机,无法事先知道是否会继续使用某些变量(在这种情况下为字节)。 但是JIT可以立即看到整个方法,因此可以推断出不再使用字节,并且实际上可以使用GC。 因此,垃圾收集最终可以发生,并且我们的程序神奇地自我修复了。 现在,我只希望没有读者真正负责在生产中调试这种情况。 但是,如果您希望使某人的生活陷入困境,那么将这样的代码引入生产环境将是实现此目标的肯定方法。

翻译自: https://www.javacodegeeks.com/2014/12/self-healing-jvm.html

jvm7 jvm8

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

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

相关文章

实例讲解C语言的位运算

C语言位运算有6种&#xff1a; &&#xff0c; | , ^(异或)&#xff0c; <<(左移)&#xff0c;>>(右移)。注意&#xff1a;参与位运算的元素必须是int型或者char型&#xff0c;以补码形式出现。1.按位与&&运算常应用于&#xff1a;迅速清零保留指定位判…

python3解释器执行not 1 and 1_编程语言的分类,python解释器多版本共存.执行python的两种方式,变量,用户与程序交互...

一、编程语言的分类&#xff1f;机器语言&#xff1a;直接使用二进制指令编程&#xff0c;直接操作硬件&#xff0c;必须考虑硬件细节。汇编语言&#xff1a;用简写的英文标识符取代二进制去编写程序&#xff0c;直接操作硬件&#xff0c;必须考虑硬件细节。高级语言&#xff1…

java字节码执行原理_《Java 底层原理》Java 字节码详解

前言我们在开发中会遇到一些Java的执行超出我们的想象&#xff0c;但是又不知道他为什么会这样执行&#xff0c;这个时候我们就需要能够知道他编译后Class文件是什么样子的&#xff0c;并且理解字节码的含义。Java字节码的原理进制class文件就是字节码文件&#xff0c;直接是打…

C语言学习笔记--位运算

这一节主要说的是位运算&#xff0c;计算机中的执行速度&#xff1a;位运算 > 加减 > 乘除 > 求余位运算就是将数字转换成二进制后进行运算&#xff0c;之后再将数字转换成原来的进制与运算&#xff1a;当两个数相与时&#xff0c;只有都为l的时候结果才为1&#xff0…

openshift学习_在OpenShift上将JMS与JBoss A-MQ结合使用。 学习了有关远程客户端和加密的经验。...

openshift学习OpenShift是“红帽开发的开放式混合云应用程序平台”。 它具有不同的风格&#xff0c;对于大多数您想做的事情&#xff0c;最有趣的部分是公共云应用程序开发和托管平台“ OpenShift Online ”。 您可以轻松地尝试一下&#xff0c;因为在云中使用OpenShift Online…

mathtype运行时错误48_在office中无法使用MathType该怎么办?

想必大家都遇到过在office中无法使用MathType的情况&#xff0c;那么遇到这种情况的话大家应该怎么来解决呢&#xff1f;首先这样的现象一般为&#xff1a;word或者ppt中没有mathtype选项&#xff0c;或者选项打开提示文件未找到&#xff1a;MathPage.WLL。错误提示或者甚至运行…

谈谈C语言中的杂项运算符

在C语言中&#xff0c;还有一些重要的运算符&#xff0c;例如&#xff1a;sizeof()、&、* 、 ?: 。我们把上述的这些运算符归为杂项运算符&#xff0c;下面我将详细介绍这些杂项运算符。下面的表格列出了 C 语言支持的所有杂项运算符&#xff1a;运算符解释例子sizeof()返…

java集合的添加方法_深入理解java集合框架之---------Arraylist集合 -----添加方法

Arraylist集合 -----添加方法1、add(E e) 向集合中添加元素/*** 检查数组容量是否够用* param minCapacity*/public void ensureCapacity(int minCapacity){modCount;int oldCapacity elementData.length;if(minCapacity > oldCapacity){Object oldData[] elementData;int…

jenkins java_具有WildFly,Arquillian,Jenkins和OpenShift的Java EE 7部署管道

jenkins java技术提示&#xff03;54展示了如何Arquillianate&#xff08;Arquillianize&#xff1f;&#xff09;一个现有的Java EE项目并在WildFly在已知主机和端口上运行的远程模式下运行这些测试。 技术提示&#xff03;55展示了当WildFly在OpenShift中运行时如何运行这些测…

matplotlib 折线图_漂亮图表也可信手拈来,一文学会用Python绘制堆积折线图

今天咱们还是接着上次的话题&#xff0c;继续和大家聊聊关于Python绘图相关的东东哦&#xff0c;上次已经和大家讨论完了如何给自己所绘制的图表中添加装饰线以及修改装饰线密度的方法&#xff0c;今天呢&#xff0c;咱们再聊点的新的东东哦&#xff0c;还是和大家继续深耕Pyth…

C语言 | 赋值与运算符

本章以鸡兔同笼为例&#xff0c;讲解赋值语句和一些简单的运算符。相关知识点&#xff1a;scanf(" %d " , &i ); 输入函数&#xff0c;表示输入一个整数&#xff08;%d&#xff09;&#xff0c;赋值给 i&#xff08;&i&#xff09;C语言中加法运算符为 减法…

菜鸟学java要多久_菜鸟学java,根本停不下来!

位运算符&: 两个2进制的操作数,同一位数的两个数如果有一个为0结果就为0,两个都为1才是1.| : 两个2进制的操作数,同一位数的两个数如果有一个为1,两个都为0才是0.^ : 两个2进制的操作数,同一位数的两个数如果相同为0,不同为1.位移运算符<< 左移:把第一个二进制的操作…

响应式多级菜单 侧边菜单栏_使用纯HTML和OmniFaces构建动态响应的多级菜单

响应式多级菜单 侧边菜单栏最近&#xff0c;我不得不使用JSF 2.2创建一个响应式多级菜单。 要求&#xff1a;菜单应&#xff1a; 从后端使用动态结构创建 React灵敏&#xff0c;例如对桌面和移动设备友好 有带有导航链接的子菜单项 支持触摸事件 支持键盘辅助功能 PrimeF…

python列表中随机两个_随机化两个列表并在python中维护顺序

随机化两个列表并在python中维护顺序说我有两个简单的清单&#xff0c;a [Spears, "Adele", "NDubz", "Nicole", "Cristina"]b [1,2,3,4,5]len(a) len(b)我想做的是将a和a随机化&#xff0c;但要保持顺序。 因此&#xff0c;类似&a…

C语言中的头文件

头文件是扩展名为 .h 的文件&#xff0c;包含了 C 函数声明和宏定义&#xff0c;被多个源文件中引用共享。有两种类型的头文件&#xff1a;程序员编写的头文件和编译器自带的头文件。在程序中要使用头文件&#xff0c;需要使用 C 预处理指令 #include 来引用它。前面我们已经看…

ceph-rest-api_快速检查REST API是否有效的方法-从清单文件中获取详细信息

ceph-rest-api在某些情况下&#xff0c;您可能想快速验证部署在开发&#xff0c;测试或生产环境中的REST API是否完全可以访问。 一种常见的实现方法是构建通用资源&#xff0c;该资源可提供例如已部署API的版本。 您可以手动触发对此资源的请求&#xff0c;或者更好的是&#…

set trans 必须是事务处理的第一个语句_MySQL中特别实用的几种SQL语句送给大家

在写SQL时&#xff0c;经常灵活运用一些SQL语句编写的技巧&#xff0c;可以大大简化程序逻辑。减少程序与数据库的交互次数&#xff0c;有利于数据库高可用性&#xff0c;同时也能显得你的SQL很牛B&#xff0c;让同事们眼前一亮。实用的SQL1.插入或替换如果我们想插入一条新记录…

C语言预处理命令总结

预处理指令是以#号开头的代码行&#xff0c;# 号必须是该行除了任何空白字符外的第一个字符。# 后是指令关键字&#xff0c;在关键字和 # 号之间允许存在任意个数的空白字符&#xff0c;整行语句构成了一条预处理指令&#xff0c;该指令将在编译器进行编译之前对源代码做某些转…

突破极限–如何使用AeroGear Unified Push for Java EE和Node.js

在2014年底的AeroGear队宣布红帽的JBoss统一推送服务器的可用性xPaaS 。 让我们仔细看看&#xff01; 总览 统一推送服务器允许开发人员将本地推送消息发送到Apple的推送通知服务&#xff08;APNS&#xff09;和Google的云消息传递&#xff08;GCM&#xff09;。 它具有内置的…

java 运行os文件路径_Java获取文件路径的几种方式

关于绝对路径和相对路径&#xff1a; 绝对路径就是你的主页上的文件或目录在硬盘上真正的路径&#xff0c;(URL和物理路径)例如&#xff1a;C:xyz est.txt 代表了test.txt文件的绝对路径。http://www.sun.com/index.htm也代表了一个URL绝对路径。相 对路径&#xff1a;相对与某…