- 博客(88)
- 收藏
- 关注
原创 JDK19虚拟线程初探(三)
总共花三篇文章大概介绍了JDK19中新增的虚拟线程,从LOOM Project的纤程、阿里的wisp和wisp2、到今天JEP 425中的虚拟线程,官方提供的生产可用的用户态线程方案距离我们越来越近了。
2022-11-12 16:27:57
729
原创 JDK19虚拟线程初探(二)
在上一篇文章中,我们已经简单的介绍了JEP 425: Virtual Threads (Preview),以及如何使用虚拟线程编写例程,本文中将继续介绍虚拟线程的底层机制和核心源码。
2022-11-11 21:32:38
875
1
原创 JDK19虚拟线程初探(一)
经过多年的等待后,JEP 425: Virtual Threads (Preview)终于带来了虚拟线程,这一轻量级的线程模型对标其他语言中的协程,能够显著的减少编写、维护和观察高并发应用程序的工作量。
2022-10-30 15:05:34
521
原创 OpenJDK16 ZGC 源码分析(八)GC阶段之并发转移
1. 简介ZGC最后一个阶段就是并发转移,在之前的阶段已经标记出了活跃对象和需要转移的page。因此并发转移阶段,GC并发的将转移集中的活跃对象迁移到新页面,并在转移完成后回收旧页面。2. 源码分析2.1 入口并发转移的转移的入口也在zHeap。hotspot/share/gc/z/zHeap.cppvoid ZHeap::relocate() { // Relocate relocation set _relocate.relocate(&_relocation_set);
2021-09-17 20:04:53
456
原创 OpenJDK16 ZGC 源码分析(七)GC阶段之转移集
1. 简介在并发处理完强引用和非强引用后,ZGC就进入了转移阶段。本文将介绍转移阶段开始的两个小步骤,重置转移集和选择转移集。2. 源码分析2.1 重置转移集在标记阶段介绍后,所有的引用都已经指向对象迁移后的新地址,ZForwardingTable中的数据已经全部失效。此时需要重置转移集,为下一轮GC做准备。hotspot/share/gc/z/zHeap.cppvoid ZHeap::reset_relocation_set() { // 重置forwarding table ZRe
2021-09-15 13:43:28
256
原创 OpenJDK16 ZGC 源码分析(六)GC阶段之非强引用处理
1. 简介在并发标记结束后,ZGC进入非强引用的并发标记和处理阶段。主要负责处理软引用、弱引用、虚引用、FinalReference(实现了Finalize方法的类的实例)。2. 引用2.1 引用的基本概念引用的类型memory/referenceType.hppenum ReferenceType { REF_NONE, // 正常的类 REF_OTHER, // java/lang/ref/Reference的子类,但不在下面里面 REF_SOFT,
2021-09-10 13:44:20
284
原创 OpenJDK16 ZGC 源码分析(五)GC阶段之并发标记
1. 简介并发标记是ZGC的第2个阶段,此阶段中,GC worker与Mutator并发工作,GC worker执行标记、load barrier和relocate。并发线程从带标记对象列表开始,递归遍历对象及对象的成员变量并标记。2. 源码分析2.1 入栈标记栈的size受ZMarkStackSpaceLimit参数控制,默认8G,合法值32MB到1TB之间。share/gc/z/z_globals.hpp product(size_t, ZMarkStackSpaceLimit, 8*G
2021-09-03 14:06:38
534
原创 OpenJDK16 ZGC 源码分析(四)GC阶段之初始标记
1. 简介GC回收周期大体如下图所示:与早期版本不同,ZGC回收周期调整为9个子阶段:phase 1:初始标记,需要STWphase 2:并发标记phase 3:标记结束,需要STWphase 4:并发处理软引用、弱引用phase 5:并发重置Relocation Setphase 6:验证phase 7:并发选择Relocation Setphase 8:开始Relocate,STWphase 9:并发Relocate出于回收效率的考虑,remap过程放在下一个回收周期的并发标记
2021-08-28 20:11:48
616
原创 OpenJDK16 ZGC 源码分析(三)读屏障Load Barrier
1. 简介对于并发GC来说,最复杂的事情在于GC worker在标记-整理,而Java线程(Mutator)同时还在不断的创建新对象、修改字段,不停的更新对象引用关系。因此并发GC一般采用两种策略Incremental Update(增量更新、CMS) 和SATB(snapshot at beginning、G1) ,两种策略网上介绍文章很多,此处不再赘述。SATB关注引用关系的删除,可以参考我之前的博客JVM G1 源码分析(四)- Dirty Card Queue Set,而Incremental
2021-08-21 19:28:54
1005
原创 OpenJDK16 ZGC 源码分析(二)对象分配
1. 简介自从JDK10中的引入了JEP 304: Garbage Collector Interface 后,OpenJDK定义了一整套关于GC的虚方法,供具体的GC算法实现。极大了简化了开发难度和代码的可维护性。JEP 304定义了CollectedHeap类,每个GC都需要实现。CollectedHeap类负责驱动HotSpot的GC,以及和其他模块的交互。GC应当实现如下功能:CollectedHeap的子类BarrierSet集合类的实现,提供在运行时各种屏障功能。CollectorP
2021-08-17 19:34:51
372
原创 OpenJDK16 ZGC 源码分析(一)内存管理
1. 概览ZGC在JDK11中作为实验性功能引入后,已经经过了5个版本的演进,目前较之前版本有了较大的变化。本文及其后几篇文章,将分析ZGC的设计思想和原理。关于ZGC的介绍,可以参考OpenJDK ZGC 源码分析(一)概览2. 简介ZGC为了支持TB级内存,采用了基于Page的分页管理(类似于G1的Region)。同时,为了加快内存访问速度,快速的进行并发标记和relocate,ZGC新引入了Color Pointers;Color Pointers与Shenandoah GC使用的Bro
2021-08-05 08:34:26
594
原创 Runtime.getRuntime().availableProcessors()方法在Docker容器中遇到的问题和解决方案
问题最近在线上环境遇到一个奇怪的问题,仅仅20qps的压测,产生非常多的毛刺,立刻判断出毛刺是由于YGC导致。线上环境为docker容器,4核8G内存,openjdk8u排查过程于是登录线上机器查看GC日志,发现GC Workers: 63,但压测服务器仅4核,不可能有63个GC线程。[GC pause (G1 Evacuation Pause) (young), 0.0054131 secs] 10 [Parallel Time: 3.6 ms, GC Workers: 63] 11
2021-03-05 00:33:50
5814
1
原创 org.apache.thrift导致的OOM
1. 背景昨日开始压测某微服务,但是发现了一个很奇怪的OOM: java heap space通过压测平台压测必现,即使QPS=1时也必现手动触发无法重现发生OOM时,GC日志显示java heap并未全部占用,但gc触发原因是GC (Allocation Failure)除了OOM日志,没有其他任何拦截器日志和业务日志虽然已经在生产环境见过很多种OOM,但这类奇怪的OOM还是第一次见到。2. 分析过程2.1 Java Dump分析OOM第一步通常就是查看dump文件,但是由于压测环境
2021-02-19 16:55:20
700
原创 select ... for update 语句的分析
1. 前言本文将介绍select … for update语句相关知识,以及对可能导致的死锁和影响进行分析。如无特殊说明,本文涉及的MySQL版本为8.0.22,事务隔离级别为RR,数据库引擎为INNODB。2. 实验数据准备创建一个测试表t_a:CREATE TABLE `test_a` ( `id` int NOT NULL, `a` int NOT NULL, `b` int NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAU
2021-01-30 11:59:33
1531
2
原创 Lambda表达式实现机制的分析
1. 背景几年前曾经写过一篇Lambda表达式实现机制的分析,现在回头看错误很多,有误导嫌疑,因此重写一版订正。2. Lambda表达式的字节码分析下面代码为一个Lambda表达式的例子package demo;import java.util.LinkedList;import java.util.List;import java.util.stream.Collectors;public class Test1 { public void func1(List<Inte
2020-10-04 23:58:15
378
原创 etcd源码阅读笔记(二)backend
1. 简介etcd的backend模块对于底层存储引擎进行了抽象,默认使用上一篇文章中介绍的BoltDB。etcd将键值对的每一个版本都存储在BoltDB中,并在内存中构建BTree keyIndex索引。在BoltDB中存储数据的key是revision,revision包含两个id:main revision和sub revision;main revision每个事务加1,sub revision事务中的每次操作加1;keyIndex索引的key是键值对的key,value是revisio
2020-05-11 18:21:31
598
原创 java.nio.file.Files lines方法使用不当引发的文件句柄泄露
1. 问题描述4月29日上午,测试同学通过压测工具测试"网关->业务层->分析服务"链路,QPS 200。测试开始不久后,CloudMonitor告警"分析服务"服务器磁盘占用超过80%,经过排查,确定告警根原因是java.nio.file.Files lines方法使用不当引发的文件句柄泄露,临时文件被删除后磁盘空间未释放导致。2. 排查步骤测试开始后10分钟左右,Clo...
2020-04-29 19:12:40
1171
原创 etcd源码阅读笔记(一)存储引擎
1. 简介etcd是一个分布式高可用的键值对存储,主要聚焦于以下能力:简单,通过gRPC调用安全,支持TLS快速,支持每秒10000次写入高可用,采用Raft算法,实现了CPetcd v2在实际应用中遇到了一些问题,如基于内存、没有提供事务、对于watcher兼容不佳等。因此v3版本存储进行了大量优化:将backend store抽象,支持多种不同存储,默认是BoltDB基...
2020-04-25 18:28:29
742
原创 缓存一致性协议简介
1. 前言最近阅读了一些UNIX系统书籍,对于多处理器系统和高速缓存的机制有了更多的理解,写下本文备忘。2. 多处理器的高速缓存架构2.1 SMP最简单的多处理器架构是一种被称为对称多处理器结构(SMP:Symmetric Multi-Processor)的架构,SMP的逻辑架构如下图:在上图中,我们可以清楚的看出SMP架构的特点:紧密耦合,所有的CPU、存储器和IO都是紧密耦合的...
2020-01-14 13:32:53
543
原创 JEP 353: Reimplement the Legacy Socket API(JDK 13)
1. 简介JDK中的java.net.Socket 和 java.net.ServerSocket实现非常古老,可以上溯到JDK 1.0,该实现是混合了JAVA和C代码,非常难于维护和调试。另外,该实现使用线程堆栈作为I/O缓冲区,这带来一系列的移植性和可用性问题。因此JDK 13中实现了新的java.net.SocketImpl的实现类sun.nio.ch.NioSocketImpl,以替代...
2019-12-03 17:10:01
288
原创 JEP-351 ZGC: Uncommit Unused Memory(JDK 13)
1. 简介将GC后的内存返回给OS这一能力,在云计算场景中将节省用户的支出。因此G1和Shenandoah均实现了该能力,在JDK 13中,ZGC也具备了该能力。由于ZGC的堆被划分为一个个的ZPage,返回OS将以ZPage为单位执行,实现较为简单,下文中将详细说明。2. 分析2.1 页缓存ZGC中使用ZPageCache缓存ZPage,ZPageCache中维护了三个LRU链表分别缓...
2019-11-28 14:20:31
785
原创 Java中的字符串存储方式
1. 简介十一放假期间在脉脉上看见一道面试题讨论的很火热:Java中字符串是如何存储的?这一问题看似简单,但是背后却隐藏了很多深层机制,本文将逐一介绍相关技术原理。2. 字符串类字符串广泛应用于Java编程中,在Java中字符串属于对象,Java提供了String 类来创建和操作字符串。2.1 java.lang.Stringjava.lang.String成员变量如下:pub...
2019-10-10 15:27:21
1213
原创 Tomcat线程池的优化
1. 简介Tomcat继承并重写了JAVA原生的java.util.concurrent.ThreadPoolExecutor,增加了一些更有效率的方法,并且默认拒绝策略为RejectedExecutionException。2. 原理分析2.1 实例化与阿里巴巴JAVA规范中定义的线程池创建规范类似,Tomcat实例化线程池时,同样限制了任务队列的长度,maxQueueSize默认为In...
2019-09-25 16:27:44
654
原创 Web服务器的线程策略
1. 简介当前主流的Web服务器如Tomcat、Jetty均已采用nio作为默认的I/O模型。通常nio的线程模型中会有一组Acceptor线程用于接收客户端连接,一组Selector线程用于监听和处理I/O事件。当Selector检测到I/O事件后,是用同一个线程执行业务逻辑,还是将事件提交到一个业务线程组执行呢?不同的应用服务器,不同的场景下有着不同的策略。本文将介绍几种主流的应用服务器的...
2019-09-24 17:26:31
509
原创 OpenJDK ZGC 源码分析(六)GC回收
1. 简介GC回收周期大体如下图所示:GC回收周期包括如下11个子阶段:phase 1:初始标记,需要STWphase 2:并发标记phase 3:标记结束,需要STWphase 4:并发处理软引用、弱引用phase 5:并发重置Relocation Setphase 6:并发销毁可回收页phase 7:内存验证phase 8:并发选择Relocation Setphas...
2019-08-16 09:56:18
932
原创 OpenJDK ZGC 源码分析(五)对象分配
1. 简介ZGC的对象分配流程大体与G1类似。分配流程图在JVM G1 源码分析(二)- 对象的堆空间分配内。主要代码在src/hotspot/share/gc/shared目录下,为多个GC算法的共用代码。ZGC定制逻辑由gc shared代码调用ZCollectedHeap、ZHeap等ZGC派生类实现。2. 源码分析2.1 allocate_new_tlab当线程的TLAB可用内...
2019-08-15 09:44:08
468
原创 OpenJDK ZGC 源码分析(四)分页
1. 简介与G1的分区类似,ZGC将堆划分成Page进行管理,不同的是ZGC中Page大小不是固定的,而是分为三种Small、Medium、Large三类。本文将详细介绍ZGC的分页机制。2. 代码分析2.1 Page的类型ZGC有3种不同的页面类型:小型(2MB),中型(32MB)和大型(2MB的倍数)。zGlobals_linux_x86.hppconst size_t Z...
2019-08-14 09:57:27
424
原创 OpenJDK ZGC 源码分析(三)内存管理
1. 简介ZGC与传统GC不同,标记阶段标记的是指针(colored pointer),而非传统GC算法中的标记对象。ZGC借助内存映射,将多个地址映射到同一个内存文件描述符上,使得ZGC回收周期各阶段能够使用不同的地址访问同一对象。本文将详细介绍ZGC的内存管理。2. 代码分析2.1 指针结构目前ZGC仅支持Linux/x64,指针是64位的,ZGC重新定义了指针结构。zGlobal...
2019-08-13 14:48:48
1067
原创 OpenJDK ZGC 源码分析(二)触发GC的时机
1. 简介ZGC的回收周期触发时机与其他GC算法略有不同,VM内部有个线程轮询定期检查是否满足开始回收的条件,如果满足则开始回收。ZGC提供四种策略,其中一种满足条件即触发回收:rule_timer,定时策略,距离上次GC时间超过interval即触发GCrule_warmup,VM启动后,如果从来没有发生过GC,则在堆内存使用超过10%、20%、30%时,分别触发一次GC,以收集GC数...
2019-08-08 12:22:10
1014
原创 OpenJDK ZGC 源码分析(一)概览
1. 前言G1是JDK中最新最成熟的垃圾回收器,其稳定性和性能得到了广泛的认可。但是,一方面随着硬件的发展,堆空间越来越大,几十GB、上百GB的内存在生产环境逐渐出现;另一方面,对于停顿时间的需求日益严苛,从最初的秒级到百毫秒级,再到十毫秒级和毫秒级。G1对于这种情况逐渐力不从心,下一代低延迟垃圾回收器主要有ZGC和Shenandoah。本文将详细介绍ZGC相关原理。2. 历史Oracle在...
2019-08-07 14:40:27
1283
原创 JVM G1 源码分析(七)- Full GC
1. 简介当晋升失败、疏散失败、大对象分配失败、Evac失败时,有可能触发Full GC,在JDK10之前,Full GC是串行的,JEP 307: Parallel Full GC for G1之后引入了并行Full GC。本文主要介绍并行Full GC机制。2. 源码分析Full GC的入口在g1CollectedHeap.cpp的G1CollectedHeap::do_full_col...
2019-08-05 16:10:47
2932
原创 JVM G1 源码分析(六)- 混合式GC
1. 简介YGC整个过程都在STW下进行,出于减少停顿时间的考量,对于老年代的回收显然需要与Mutator同时进行,G1引入了混合式GC,与CMS算法类似,均采用了并发标记。混合式回收主要分为如下子阶段:初始标记子阶段并发标记子阶段再标记子阶段清理子阶段垃圾回收2. 算法概览2.1 标记算法概览由于混合式GC使用的是并发标记,Mutator可能会随时改变对象引用关系,从而导...
2019-08-01 15:18:05
1614
1
原创 JVM G1 源码分析(五)- 新生代回收YGC
1. 简介G1的YGC仅针对标记为新生代的Region进行回收,因此YGC花费的时间较少。正如之前章节所介绍的,一个Region属于老年代还是新生代时动态的,每次YGC都会回收全部新生代Region,并在之后的内存分配流程中重新分配Region给新生代。2. 代码分析2.1 YGC的流程YGC的流程如下:首先STW,YGC全过程都在STW时进行,不需要考虑并发场景选择CSet(Co...
2019-07-30 17:10:15
3143
2
原创 JVM G1 源码分析(四)- Dirty Card Queue Set
1. 简介在上篇文章中,我们介绍了RSet的原理,当对象引用关系变化时,都需要更新RSet。为了不影响Mutator的性能,RSet的更新通常是异步进行的,这一异步更新操作需要引入DCQS(Dirty Card Queue Set)结构。本文将分析DCQS的原理。2. DCQS2.1 写入DCQSJVM声明了一个全局的静态结构G1BarrierSet,其中包含两个Queue Set,Di...
2019-07-29 11:44:49
2509
原创 JVM G1 源码分析(三)- Remembered Sets
1. 简介记录集Remembered Sets简称RSet,用于记录对象在不同分区之间的引用关系,目的是为了加速垃圾回收的速度,主要是加速标记阶段。本文将详细介绍RSet的结构。通常的,有两种记录引用关系的方式,PointOut和PointIn。如果obj1.field1=obj2,如果是PointOut方式,则在obj1所在region的RSet记录obj2的位置;如果是PointIn方...
2019-07-25 17:26:37
3476
原创 JVM G1 源码分析(二)- 对象的堆空间分配
1. 简介当开发者使用JAVA语言实例化一个对象时,排除JIT的标量替换等优化手段,该对象会在JAVA Heap上分配存储空间。分配空间时,为了提高JVM的运行效率,应当尽量减少临界区范围,避免全局锁。G1的通常的应用场景中,会存在大量的Mutator同时执行,为减少锁冲突,引入了TLAB(线程本地分配缓冲区 Thread Local Allocation Buffer)机制。G1支持基于T...
2019-07-23 14:15:16
1889
1
原创 JVM G1 源码分析(一)- 分区Heap Region
1. 简介G1(Garbage-First Collector)是一种垃圾回收算法,最早在JDK 6 Update 14中作为实验性功能加入,并在JDK 7 Update 4正式JDK,之后在JDK 9 中成为默认垃圾回收算法,在JDK 10中优化了Full GC性能。G1是面向服务器的垃圾收集器,针对于多核处理器、大堆的服务器场景。它可以满足短停顿的同时支持高吞吐量。本文及随后几篇文章将分...
2019-07-22 14:54:42
2961
原创 Ehcache的缓存淘汰机制
1. 简介正如上篇文章所说,Ehcache采用了多级缓存堆内、堆外、磁盘,每级缓存容量递增,最底层被称为Authoritative Tier,其余的缓存层被称为Caching Tier。Authoritative Tier层数据是最全的,其余层的数据都是该层的数据子集,只是临时存储数据。当Caching Tier容量不足时,Ehcache将触发淘汰机制,本文将详细介绍淘汰机制的原理。2. 代...
2019-07-16 18:56:06
2129
原创 Ehcache的多级缓存机制
1. 简介Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存、Java EE和轻量级容器。它具有堆内内存、堆外内存、磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序等特点。本文将介绍堆内内存、堆外内存、磁盘存储多种存储介质组合的缓存模式及原理分析。2. 分级缓存设计作为本地缓存框架, Ehcache支持多层缓存模式,常用的有三种数据存储介质:堆内直接在JVM堆中存...
2019-07-10 13:35:50
1595
原创 Apache Flink JobManager HA机制
1. 简介在Flink部署架构中,JobManager负责协调Flink任务调度和资源管理。默认情况下,每个Flink集群都有一个JobManager实例,这会产生单点故障(SPOF single point of failure),如果JobManager进程崩溃,则无法提交新任务且运行中的任务也会失败。启用JobManager HA后,就可以JobManager崩溃故障中恢复,消除单点故...
2019-07-01 16:43:24
858
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人