JVM
文章平均质量分 92
黄智霖-blog
骨灰级技术爱好者
展开
-
深入OpenJDK源码全面理解Java类加载器(下 -- Java源码篇)
目录前言一、双亲委派1.1 类加载器结构1.2 双亲委派二、使用步骤1.引入库2.读入数据总结前言 在深入openjdk源码全面理解Java类加载器(上 – JVM源码篇)我们分析了JVM是如何启动,并且初始化BootStrapClassLoader的,也提到了sun.misc.Launcher被加载后会创建ExtClassLoader和AppClassLoader。这篇文章主要从Java源码层面总结一下双亲委派、TCCL的应用等,然后在聊聊自定义类加载器的注意事项。一、双亲委派1.1 类加载器原创 2021-03-21 04:27:29 · 10378 阅读 · 16 评论 -
垃圾收集之Remember Set(CardTable)
JVM为了更好的管理内存,提高GC效率,一般都会对内存进行划分,比如经典的分代收集,G1推出的Region等。而Java中的垃圾收集基本都基于可达性分析算法,这就涉及到对象枚举遍历和标记的过程。在做Minor GC的时候会对年轻代进行根节点枚举,但是如果年轻代中的一些对象被老年代引用着,那么在做年轻代可达性分析的时候就会遇到很大的阻碍,总不能在Minor GC的时候还去扫描老年代吧?这种跨代引用的问题抛开出现频率,它总是会存在,而且在G1这种多Region结构中更加突出(包括ZGC、Shenandoah原创 2021-03-31 01:40:11 · 4351 阅读 · 3 评论 -
深入OpenJDK源码-偏向锁的延时生效如何实现的
关于偏向锁,包括撤销和重偏向在前面已经结合源码分析过了,这里就不再赘述,主要看看延时生效的问题。另外,本文贴出的源码大多都只保留了当前关注的逻辑。 我们知道虚拟机为我们提供了参数- XX:+UseBiasedLocking以开启或者关闭偏向锁优化(默认开启),但是偏向锁的启用有个默认的延时时间,可以通过参数- XX:BiasedLockingStartupDelay设置,默认为4秒,可以在globals.hpp中找到默认值设置: product(intx, BiasedLockingStartu.原创 2021-03-30 23:45:49 · 5703 阅读 · 4 评论 -
深入OpenJDK源码--你真的了解System.out.println吗?
目录一、前戏二、JVM源码分析三、坑?四、总结一、前戏 可能不少小伙伴习惯在代码中使用sout打印一些信息,就像这样:System.out.println("hello world!") 做为一位资深干码人,本着弘扬党求真务实的精神,必须得来看看这个sout有何玄机~~ 首先看调用就知道,out是System类的一个公共静态成员变量,进入System.java中:public final static PrintStream out = null; 嗯,不止是public,还是fi原创 2021-03-30 02:10:24 · 8174 阅读 · 16 评论 -
可达性分析之三色标记算法详解
二、三色标记在前文中提到了,在CMS的并发清理阶段才产生的垃圾,会被当做浮动垃圾,会留到下一次GC再清理。其实在并发标记阶段,由于用户线程在并发运行,也就可能导致引用关系改变,导致标记结果不准确,从而引发更加严重的问题,这些发生变更的数据会在重新标记阶段被处理,那么会出现什么问题?又是如何处理的呢?CMS算法的基础是通过可达性分析找到存活的对象,然后给存活的对象打个标记,最终在清理的时候,如果一个对象没有任何标记,就表示这个对象不可达,需要被清理。并发标记阶段是从GC Root直接关联的对象开始枚举的原创 2021-03-30 02:11:16 · 12159 阅读 · 15 评论 -
垃圾收集器总结--CMS垃圾收集器
目录一、CMS1.1 概述1.2 内存碎片1.3 浮动垃圾1.4 空间预留1.4 Promotion Failed和Concurrent Mode Failure1.5 常用参数二、总结一、CMS1.1 概述 CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,其主要优点就是并发收集、低停顿。适合重视服务响应速度的应用的服务器,基于标记-清除算法,用于老年代。它是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次基本上实现了让垃圾收集线程与原创 2021-03-28 22:49:46 · 3137 阅读 · 0 评论 -
《深入理解Java虚拟机》读书笔记(十)--晚期(运行期)优化(下)
目录一、公共子表达式消除二、数组边界检查消除三、隐式异常处理四、方法内联五、逃逸分析六、Java与C/C++的编译器对比一、公共子表达式消除 如果一个表达式E已经计算过了,并且从先前的计算到现在E中所有变量的值都没有发生变化,那么E的这次出现就成为公共子表达式。对于这种表达式,没有必要花时间再对它进行计算,只需要直接用前面计算过的结果代替E就行了。如果这种优化仅限于程序的基本块内,便称为局部公共子表达式消除,如果优化的范围涵盖了多个基本块,就称为全局公共子表达式消除。 对于以下代码:int d原创 2021-03-27 03:07:21 · 3838 阅读 · 4 评论 -
《深入理解Java虚拟机》读书笔记(十)--晚期(运行期)优化(上)
文章目录一、HotSpot虚拟机内部的即时编译器1.1 解释器和编译器1.2 编译对象和触发条件1.2.1 方法调用计数器1.2.2 回边计数器1.3 编译过程二、编译优化技术2.1 方法内联2.2 冗余访问消除2.3 复写传播2.4 无用代码消除一、HotSpot虚拟机内部的即时编译器1.1 解释器和编译器 当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行。在程序运行后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编译成本地代码之后,可以获得更高的执行效率。原创 2021-03-25 01:47:55 · 5404 阅读 · 6 评论 -
《深入理解Java虚拟机》读书笔记(九)--早期(编译期)优化
目录一、Javac编译器1.1 解析与填充符号表1.1.1 词法、语法分析1.1.2 填充符号表1.2 注解处理器1.3 语义分析与字节码生成二、使用步骤1.引入库2.读入数据总结一、Javac编译器Javac的编译过程大致可以分为3个过程,分别是:解析与填充符号表过程插入式注解处理器的注解处理过程分析与字节码生成过程1.1 解析与填充符号表1.1.1 词法、语法分析 词法分析是将源码的字符流转变为标记(Token)集合,单个字符是程序编写过程的最小元素,而标记则是编译过程的最小元原创 2021-03-23 03:00:28 · 6113 阅读 · 2 评论 -
深入OpenJDK源码全面理解Java类加载器(上 -- JVM源码篇)
目录前言一、从JDK源码看双亲委派二、使用步骤1.引入库2.读入数据总结前言关于JVM类加载的基础理论知识,请参照《深入理解Java虚拟机》读书笔记(六)–虚拟机类加载机制(上)和《深入理解Java虚拟机》读书笔记(六)–虚拟机类加载机制(下)。一、从JDK源码看双亲委派注:博主是使用的是openjdk8,换了新电脑还没有去编译源码,所以看的是静态代码,关于如何编译和调试源码,网上不少文章都有介绍,这里就不赘述了我们都知道在Java类加载中,除了BootStrap加载器,App和Ext加载原创 2021-03-19 13:14:48 · 18232 阅读 · 29 评论 -
关于使用MethodHandle在子类中调用祖父类重写方法的探究
注:这个例子本出现在周志明先生的《深入理解Java虚拟机》虚拟机字节码执行引擎章节,介于有读者朋友有疑问,这里解释一下(原文在《深入理解Java虚拟机》读书笔记(七)--虚拟机字节码执行引擎(下))。这里直接把代码列出来:package test;import java.lang.invoke.MethodHandles;import java.lang.invoke.MethodType;import java.lang.reflect.Field;public class Te.原创 2021-03-11 13:25:50 · 5257 阅读 · 8 评论 -
《深入理解Java虚拟机》读书笔记(七)--虚拟机字节码执行引擎(下)
一、Java动态类型语言支持动态类型语言的关键特征是它的类型检查的主体过程是在运行期而不是编译期,满足这个特征的语言有很多,比如JavaScript、Python等,相对的,在编译期就进行类型检查的语言(如C++/Java等)就是最常用的静态类型语言。例如以下代码:obj.println("hello world");假设这行代码在Java语言中,并且变量obj的静态类型为java.io.PrintStream,那么变量obj的实际类型就必须是PrintStream的子类(实现了Print原创 2021-03-08 00:10:32 · 11106 阅读 · 29 评论 -
《深入理解Java虚拟机》读书笔记(七)--虚拟机字节码执行引擎(上)
目录前言一、运行时栈帧结构1.1 局部变量表1.2 操作数栈1.3 动态连接1.4 方法返回地址1.5 附加信息二、确定执行方法2.1 解析2.2 分派2.2.1 静态分派2.2.2 动态分派2.2.3 单分派和多分派2.2.4 虚拟机动态分派的实现前言本章主要讲述虚拟机如何确定调用方法的版本和如何执行方法。一、运行时栈帧结构1.1 局部变量表用于存放方法参数和方法内定义的局部变量。在编译阶段,就在方法表的Code属性的max.原创 2021-03-07 02:18:30 · 7692 阅读 · 10 评论 -
MAT分析dump文件显示大小比jmap查询结果小
一、场景原创 2021-03-04 22:08:16 · 18610 阅读 · 14 评论 -
《深入理解Java虚拟机》读书笔记(六)--虚拟机类加载机制(下)
一、类加载器与类通过一个类的全限定名来获取描述此类的二进制字节流,实现这个动作的代码模块称为“类加载器”。用户可以使用自定义的类加载器,以此自己决定如何去获取所需要的类。在虚拟机中,对于任何一个类的唯一性是由加载它的类加载器和这个类的全限定名共同确定的,每一个类加载器都有一个独立的类命名空间。这里需要注意的是,对于相同全限定名的类,如果类加载器不同,会影响到类的Class对象的equals()方法、isAssignableFrom()方法、isInstance()方法的返回结果,也会影响使用inst原创 2021-03-03 23:54:22 · 10899 阅读 · 4 评论 -
《深入理解Java虚拟机》读书笔记(六)--虚拟机类加载机制(上)
一、概述所谓类加载机制,就是虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。Java的类加载、连接和初始化过程都是在程序运行期间完成的,这虽然会让类加载时增加性能开销,但是提供了高度的灵活性。二、类加载的时机类的整个生命周期包括加载、验证、准备、解析、初始化、使用和卸载7个阶段,其中验证、准备、解析3个部分统称为连接。其中,加载、验证、准备、初始化和卸载5个阶段的顺序是固定的,类加载需要按照这种顺序开始(只是原创 2021-03-01 01:14:13 · 3829 阅读 · 6 评论 -
《深入理解Java虚拟机》读书笔记(五)--类文件结构
注:书中第五章-调优案例分析与实战,包含几个案例分析和eclipse调优,但是其中的例子很简单,就先不整理到笔记里了原创 2021-02-28 16:15:31 · 7001 阅读 · 21 评论 -
通过字节码理解try-catch-finally
对于以下代码:public int test() { int x; try { x = 1; return x; } catch (Exception e) { x = 2; return x; } finally { x = 3; } }结论:如果trye语句没有出现属于Exceptio原创 2021-02-28 01:12:16 · 4449 阅读 · 6 评论 -
《深入理解Java虚拟机》读书笔记(四)--虚拟机性能监控与故障处理工具
一、JDK命令行工具此书是第二版,本章介绍的工具基于Windows平台下的JDK 1.6 Update 21。1.1 jps:虚拟机进程状况工具可以列出正在运行的虚拟机进程,并显示虚拟机执行主类名称(main函数所在类)以及这些进程的本地虚拟机唯一ID(Local Virtual Machine Identifier,LVMID)。其常用选项见下表;jps工具主要选项 选项 作用 -q 只输出LVMID -m 输出虚拟机进程启动时传递给main函数的参数 -l原创 2021-02-22 00:42:20 · 4369 阅读 · 6 评论 -
《深入理解Java虚拟机》读书笔记(三)--垃圾收集器与内存分配策略(下)
目录一、垃圾收集器1.1 Serial收集器1.2 ParNew收集器1.3 Parallel Scavenge1.4 Serial Old收集器1.5 Parallel Old收集器1.6 CMS收集器1.7 G1收集器二、GC日志三、GC分类四、对象分配与空间分配担保五、总结一、垃圾收集器Java虚拟机规范中对垃圾收集器应该如何实现没有任何规定,因此不同的厂商、不同版本的虚拟机所提供的垃圾收集器都可能会有很大差别,并且一般都会提供参数供用户根据自己原创 2021-02-21 02:49:19 · 5069 阅读 · 7 评论 -
《深入理解Java虚拟机》读书笔记(三)--垃圾收集器与内存分配策略(上)
一、垃圾回收1.1 判断对象是否可用判断对象是否可用主要有两种方法:引用计数法和可达性分析。引用计数法:给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加1;当引用失效时,计数器就减1;任何时刻计数器为0的对象就是不再被使用的。python、Squirrel等使用这种算法。优点:实现简单,效率高缺点:可能出现循环引用(A引用B,B引用A,除此之外再没有任何地方引用A和B,由于两者相互引用,计数不为0)可达性分析:通过一系列的被称为“GC Roots”的对象作为起始点,从这些节原创 2021-02-18 01:31:56 · 7807 阅读 · 13 评论 -
《深入理解Java虚拟机》读书笔记(二)--自动内存管理机制
目录一、运行时数据区域1.1 程序计数器1.2 虚拟机栈1.2.1 局部变量表1.3 本地方法栈1.4 堆1.5 方法区1.5.1 运行时常量池1.5.2 本地直接内存二、HotSpot 虚拟机对象探秘2.1 对象的创建2.1.1 内存空间分配2.2 对象内存布局2.2.1 对象头2.2.2 实例数据2.2.3 对齐填充2.3 对象的访问定位2.3.1 句柄2.3.2 直接指针三、总结一、运行时数据区域Java虚拟机在执原创 2021-02-17 01:47:34 · 9214 阅读 · 15 评论 -
《深入理解Java虚拟机》读书笔记(一)--Java和Java虚拟机发展
目录一、Java发展史二、Java虚拟机(部分)2.1 Sun Classic VM2.2 Sun Exact VM2.3 Sun HotSpot VM2.4 BEA JRockit VM2.5 BEA Liquid VM2.6IBM J9 VM2.7 Azul VM2.8 Microsoft JVM三、总结一、Java发展史1991年4月,James Gosling博士领导绿色计划(Green Project),产品为Java语言的前身:Oak(橡树).原创 2021-02-16 21:47:35 · 4832 阅读 · 5 评论 -
不重启JVM动态添加日志(阿里Arthas)
如果生产环境临时出现故障,但是现运行代码未打印定位问题所需要的日志,我们通常的做法是添加日志->重新发布->重现故障。但是这样麻烦不说,最重要的是重启节点会丢失现场,也不一定能重现问题。所以我们希望找到一个不重启应用,能够动态增加日志的方法。原创 2021-01-28 00:26:29 · 7907 阅读 · 7 评论 -
windows下jetty配置jvm启动参数
命令行到jetty安装目录执行以下指令:D:\work\jetty>java -jar start.jar --add-to-start=jvmINFO: jvm initialised in ${jetty.base}\start.ini (appended)D:\work\jetty>--add-to-start表示启用一个模块,包括http,webapp,deploy等等,语法为: --add-to-start=<module-name1&...原创 2020-09-22 23:46:21 · 24824 阅读 · 0 评论 -
深入OpenJDK源码核心探秘Unsafe(含JNI完整使用流程)
一、介绍在Java中,sun.misc.Unsafe可以认为是用于JDK内部使用的工具类,它将一些需要使用native语言实现的功能通过java方法暴露出来,这些方法比较“危险”,因为它们可以直接修改内存中的值。通常情况下,我们并不能直接在程序中使用Unsafe,Unsafe的构造方法被私有化,语法层面上只能通过其提供的公共静态方法getUnsafe获取Unsafe实例:theUnsafe...原创 2019-10-19 23:54:52 · 12307 阅读 · 2 评论 -
Java对象内存布局概述
以HotSpot虚拟机为例,对象在内存中可以分为三块区域:对象头、实例数据和对齐填充。其中,对象头包含Mark Word和类型指针,关于对象头的内容,在gitchat中对其实现和原理都已经结合openjdk源码进行了详细的说明,其也不是本博文的主题,这里就不细说了;实例数据部分则是对象真正存储的有效信息,包含代码中所定义的字段内容;对齐填充则不是必须存在的,只是起占位符的作用,比如Hot Spot...原创 2019-09-25 23:21:00 · 9206 阅读 · 2 评论 -
Hot Spot虚拟机新生代为什么是一个eden+2个survivor
注:本文针对Hot Spot虚拟机一、分代收集在很多时候,JVM中对象的生命周期差距较大,部分对象可能是“朝生夕死”的(大部分),而部分对象可能又是比较“命长”的(小部分)。所以根据对象生命周期的特点,我们将堆空间分为几个区域,比如新生代、老年代,在不同的分代可以采取不同的收集算法,以最大化效率。二、新生代与复制算法不考虑特殊情况,对象会优先分配到新生代,并且对象大多都是朝生夕死的...原创 2019-08-27 23:53:50 · 18178 阅读 · 4 评论