云上Java System Profiling与Debugging——蚂蚁金服观察与实践-CSDN.NET
常见问题解决思路
下面介绍一下处理一些常见的问题时,使用ZProflier和ZDebugger系统与使用传统工具在流程和思路上的一些区别。一个新上线的系统如果处理能力达不到我们的预期,或者一个老的系统处理速度突然下降了,抑或频繁抛出异常,这些都促使我们去思考系统存在性能问题该优化了,那我们通常会碰到的性能问题有OOM、CPU占用率高、Load高、频繁GC等。OOM的现象为Java进程直接退出,出错日志里可以看到OutOfMemoryError的异常。如果发现频繁的做MajorGC甚至是FullGC,一般也是OOM的前兆。解决此类问题的主要手段是分析heapdump。
JDK自带jmap工具,使用命令jmap-dump:live,format=b,file=heap.bin即可将Java进程的heap内存按照HPROFBinaryFormat的格式dump
图1ZProfiler
到名字为heap.bin的文件里。命令中的live参数,意味在dump之前会做一次FullGC,保证dump出来的对象都尽量是活的对象,减少heap.bin的大小,降低工具的分析时间。是否要设置这个参数要视具体问题,比如想知道old区到底为什么会增长这么快,都增加了些什么对象呢?这个时候你可能没必要去加live参数了,只要连续做两次heapdump,然后做一次内存对比,就知道这段时间内增加了哪些对象。但如果你想找出一些长时间不释放的对象,分析其根引用树是怎样的,这时加上live参数来dump就比较合理。
常用的heapdump分析工具是EclipseMemoryAnalyzerTool,简称MAT。这款工具功能很强大,但正由于它过于强大,因此给初学者带来的学习成本也比较高。其次它是一个客户端程序,需要安装在本地,因此它也受限于本地的机器性能,比如本机内存就4GB,而heap文件大小为8GB,这时MAT就无法完成分析工作了。因为MAT本身也是Java程序,它在分析大heap时会出现不断做GC,甚至fullgc等异常情况,导致分析没有结果。针对这些问题,我们的性能分析产品ZProfiler精减了部分不常用的功能,保证绝大部分用户使用上的简便性。另外ZProfiler是个Web系统,运行在一台服务器上,分析能力不再受限于开发人员的机器性能,而WebUI操作的方式也大大减轻了开发人员的工作量。
CPU高的问题需要分层来考虑,首先检查操作系统层面的一些原因,比如频繁的memorypaging,可能导致Java应用在内核态花费的时间较多。也可以使用perftop检查JVM内部比如JIT,GC线程的CPU使用情况。如果JIT线程使用的CPU较高,就需要看看codecache或者其他JIT相关参数是否设置合理;如果是gc线程,就需要进一步分析gclog,然后调整GC相关的参数等。
排除以上原因之后,基本可以确认是Java代码的问题,可以使用ZProfiler提供了HotMethodProfiling功能查看热点方法,这个后面有详细描述。
Load高意味着运行的线程或者运行队列里的线程比较多,此时可以通过线程dump进行排查。线程dump,可以使用JDK自带的工具jstack,执行命令jstack即可,会将进程的所有Java线程给dump出来。如果还想跟踪native的堆栈,需要增加-m参数。当拿到线程dump之后,按照线程状态进行归类【注:JVM里dump出来的线程日志,线程的状态并不是100%的准确,细节可以参考JVMBug:多个线程持有一把锁?】。对于同一个系统,Load高的机器RUNNABLE态的线程数目一定比Load低的机器多。我们可以通过threaddump来分析这些多出的线程都在干嘛,从而找到Load高的原因。
针对线程分析,ZProfiler不仅仅从状态粒度提供了分析,还从锁粒度以及热点栈粒度做了统计分析,ZProfiler可以帮助用户看到一把锁影响到了哪些线程,哪个线程持有这把锁,那些线程正在等待这把锁,对于线程数因为同步锁的问题突然大增基本可以通过ZProifiler的分析结果看出问题在哪里。同样的,对于某个方法在哪些线程里或者运行态的线程里正在栈上执行,ZProfiler也提供了统计,方便用户排查Load高等问题。
图2 ZDebugger
GC频繁是Java程序最常见的问题之一,大多数情况下都是由于相关参数配置不合理导致的。HotSpotGC相关的设置参数比较多,要找到比较合理的参数设置,首先要对应用的内存情况有一个总体的了解:比如应用运行稳定后,LiveDataSize大概是多少,这个会影响到-Xmx/-Xms/-Xmn的设置大小【注:CharlieHunt/BinuJohn合写的JavaPerformance提供了很好的Guide】;运行过程中创建的对象temp对象和longlived对象的大概比率,这个会影响到heap老区新区的设置比例。
查看GC情况通常有两种方式,一种是打开gclog相关的参数,事后分析gclog;另外一种是实时获取GC信息,可以打开JMX接口通过相关的MXbean获取,或者通过jstat命令。
gclog分析是个苦差,因为gclog输出的信息非常多,但是很多时候我们需要关注的是长期的趋势和整体的统计信息,人工分析太耗时间。目前也有一些不错的gclog分析工具,比如GCViewer。ZProfiler除了做了和GCViewer类似的工作之外,前面谈到过,ZProfiler系统本身就是部署在金融云里的,这意味着用户可以非常方便地通过简单的WebUI操作把gclog直接复制到ZProfiler上来分析。另外,我们也正在开发一些更高级的一些功能,在gclog分析完成后,给用户一些直接的建议,比如是否GCPause的时间过长,设置的GC参数应该如何调整,GC花费的CPU时间是不是过长等。
实时获取GC信息方面,VisualVM的VisualGC插件做的不错,非常直观地显示出当前应用的GC情况,但是分析方面做的不够。ZProfiler同样使用MXBean的方式获取实时的GC信息,将更有价值和更具统计意义的信息展示出来。而对于云上难以复现、偶发性的问题,我们推荐使用在线调试平台ZDebugger对运行中的程序进行在线调试。在线调试的原则是方便用户简单快速地打开调试器,且不能影响应用的正常运行。基于此思路,ZDebugger设计为基于Jetty的Web服务器,用户使用浏览器即可发送调试命令。调试器使用JDWP协议通过网络与被调试的JVM后端连接,在不重启JVM的情况下动态打开JVM调试功能,JVM在不阻断应用运行的前提下即时抓取断点处的运行信息并将其返回。
JDK定制
最后谈一下我们在OpenJDK中的一些定制。主要加入了Debug-on-Late-Attach(aka.DOLA)、Fast-SnapshotAt-Breakpoint(aka.FSAB)以及HotMethodProfiling等功能【注:后续我们也会和OpenJDK社区讨论怎么能把这些改动标准化,并贡献到社区,其中的一些部分已经开始了讨论】。
DOLA即在不重新启动JVM的情况下,可以把“有限的”的Java调试功能打开。这个功能对于生产环境的调试来说非常有意义。尽管目前主流的商业JVM基本都宣称“full-speeddebugging”,但在实际的使用中,我们没有多少人直接把JVM的调试能力在生产环境直接打开【注:在JVM启动时加-agentlib:jdwp设置参数,就可以打开JVM调试】,因为事实上还是对应用的性能有影响的。比如,对于JIT的影响,调试模式下EscapeAnalysis功能是被自动关掉的,而且一些解释器的fastpath也可会受到影响,而走slowpath。所以当线上问题出现时,往往要求重新启动问题JVM,把Debug功能打开调试,而尴尬在于,重启JVM往往会导致很难再现问题场景。这个是我们改造JDK,加入DOLA的初衷。
DOLA允许用户通过jcmd命令动态把JVM的“有限的”调试功能打开,通过ZDebugger,用户可以对被调试的JVM设置断点以及查看变量的值,这两个功能对我们来说已经足够帮助我们发现和诊断线上的大部分问题。
DOLA定制解决的难点主要在这么几个方面。
- jdwpagent改造,支持Agent_OnAttach接口,这样可以通过扩展的jcmd命令把jdwpagent在运行时加载到TargetJVM。
- Interpreter改造,在Bytecodepatch路径上支持断点设置逻辑【注:关于HotSpotBytecodepatch,感兴趣的读者可以参考RewriteBytecodes/RewriteFrequentPairs等相关实现机制】。
- 方法De-optimization机制改造:标准的HotSpotJVM实现,用户设置断点,设置断点的当前方法被deoptimize到解释器版本。而我们定制的HotSpot会把所有的方法在这个点上都de-optimize掉,这是由于我们在JVM启动的时候没有开启调试,JIT就没有记录用于设置断点的方法dependency信息,De-optimize所有的方法会帮助JIT在后续的编译版本里记录下dependency信息。
FSAB的作用是配合Zdebugger系统的watchpoint调试模式。这种模式借鉴自Google的clouddebugger,其应用场景是:在云环境中,传统的SingleStep调试模式根本不可行,因为设置断点并单步调试,会造成线程阻塞,导致系统出现超时等各种无关的错误,甚至威胁整个系统正常运行。
而watchpoint调试模式是在断点停住之后,自动将调用堆栈、各层的局部变量,以及用户设置的表达式的值快速地取出来,然后Disable断点,并Continue当前执行。断点需要用户主动Enable,才会再次生效。这种模式可以尽量减少调试动作对运行系统的影响。
取局部变量最早是直接使用jdi接口实现的。为了一次断点触发能给用户提供足够的信息,会递归地将每个局部变量的成员都取出来。当设置为递归四层的时候,jdi的性能问题暴露了出来,断点触发之后停顿时间长达几秒钟。因此我们扩展了jdwp,增加了FSAB,使用Native方法直接批量获取数据。
另外我们还提供了两项比较独特的功能。一个是基于watchpoint调试模式的“多人在线调试”,即ZDebugger可以让用户创建或者订阅自己感兴趣的断点,当断点触发时将相关信息推送给订阅该断点的用户。这样多个用户可以互不干扰地对同一个运行系统进行调试。另一个是自动跟踪用户关注的数据。首次断点触发后,通过FSAB获取局部变量成员数据的时候默认是广度遍历。最终在用户界面上的展示是一颗可以展开的树,用户展开去查看自己关注的成员。这时系统会记录下用户关注的是哪个成员,下次断点触发通过FSAB获取数据时,会根据用户关注成员的路径进行深度遍历。获取更多用户关注的路径上的数据,而忽略其他分支。
HotMethodProfiling顾名思义就是热点函数剖析。热点函数统计剖析是性能分析中很重要的一项工作。因为按照已有的经验,程序运行过程中大部分时间都花费在少量的代码上。为了优化工作的投入产出比,应该先考虑优化程序中的热点函数。
热点函数统计有两种方法,一种是插桩,一种是采样。前者的例子有gprof,通过编译时增加一个特殊的编译选项,在所有函数的入口和出口插桩。运行时,在桩函数中记录时间等信息,输出到结果文件。事后可以得到每个函数精确的调用次数、执行时长以及整个函数调用关系图。其缺点是需要重新编译,而且要程序运行结束后才能拿到结果。后者的例子如perf,通过高频率的定时中断去打断运行中的程序,并在中断处理中记录当前程序运行的上下文信息。这样的结果显然是一种统计意义上的结果。如果采样频率不够高(出于性能考虑,一般也不会特别高),有可能会漏掉一些频繁执行,但每次执行时间短于采样间隔的代码。但其优点是不用重编程序,随时动态开关,马上就能得到结果。
ZProfiler采用是后一种方法。因为在用户态程序中,无法像perf一样采用硬件中断,而是采用了定时信号(linux系统提供了一种SIGPROF定时器)。我们提供了start和stop两个jmx命令,其实就是启动和停止一个定时器。在定时器信号的处理函数中去回溯Java调用栈。
回溯Java调用栈,ZProfiler使用了HotSpotJVM的一个非标准接口AsyncGetCallTrace(据说Oracle商业软件JavaMissionControl的MethodProfiling也是用的这个接口)。通过调用这个接口可以获得当前被定时器信号打断的线程的Java调用栈,而不需要等到JVM的safepoint才能收集线程堆栈。依赖safepoint来收集堆栈(比如通过调用Thread.getAllStackTraces)的profiling机制是有缺陷的,往往收集到的热点堆栈并不精确。在运行JITed的代码情况下,safepoint的时机往往是由JIT来决定的,比如在执行一些非常Hot的循环时,为了保证执行效率,JIT生成的代码就不会插入safepoint的轮询。这样的情况下,依赖safepoint的profiling机制就不会profiling到这些热点。有关AsyncGetCallTrace的使用,感兴趣的读者可以在网上找到更多的资料,或者可以直接阅读HotSpot的源代码,理解它的原理和用法。
Arduino教程汇总贴(2014.12.29更新)-Arduino中文社区
初识arduino http://www.arduino.cn/thread-1083-1-1.html
关于Arduino及其周边配件的购买建议 http://www.arduino.cn/thread-11017-1-1.html
常见arduino版本比较 http://www.arduino.cn/thread-1192-1-1.html
关于使用Arduino做开发的二三理解 http://www.arduino.cn/thread-5414-1-1.html
Arduino IDE下载 http://www.arduino.cn/thread-5838-1-1.html
Arduino驱动安装方法 http://www.arduino.cn/thread-1008-1-1.html
Arduino驱动安装失败的解决方法:
Arduino驱动问题一键修复工具beta http://www.arduino.cn/thread-12349-1-1.html
安装驱动数据无效 http://www.arduino.cn/thread-7531-1-1.html
系统找不到指定文件 http://www.arduino.cn/thread-2485-1-1.html
Arduino入门套件官方视频教程 http://edu.elecspark.com/course/1
Arduino Robot官方视频教程 http://edu.elecspark.com/course/2
Arduino语言参考 http://www.arduino.cn/reference
Cooper Maa的Arduino教程(适合用各种元件学习Arduino的朋友) http://www.arduino.cn/thread-2814-1-1.html
海神的Arduino模块使用教程(适合用Arduino模块的朋友) http://www.arduino.cn/thread-3274-1-1.html
珜羽的教程(通俗易懂) http://www.arduino.cn/thread-4435-1-1.html
2.扩展库的使用
Arduino教程(提高篇)——SR04超声波类库的使用 http://www.arduino.cn/thread-1003-1-1.html
Arduino教程(提高篇)——舵机的驱动 http://www.arduino.cn/thread-1038-1-1.html
Arduino教程(提高篇)——使用EEPROM断电也能保存数据 http://www.arduino.cn/thread-1157-1-1.html
用共用体结构保存其他类型的数据到EEPROM: http://www.arduino.cn/thread-2684-1-1.html
Arduino教程(提高篇)——红外遥控(接收篇) http://www.arduino.cn/thread-1220-1-1.html
Arduino教程(提高篇)——红外遥控(发射篇) http://www.arduino.cn/thread-1394-1-1.html
使用IRremote库红外遥控家里的电器 http://www.arduino.cn/thread-3618-1-1.html
Arduino教程(提高篇)——驱动12864LCD模块 http://www.arduino.cn/thread-1930-1-1.html
3.进阶
Arduino教程(提高篇)——外部中断的使用 http://www.arduino.cn/thread-2421-1-1.html
Arduino教程(提高篇)——编写扩展库 http://www.arduino.cn/thread-1009-1-1.html
Arduino教程(提高篇)——使用Visual Studio开发Arduino http://www.arduino.cn/thread-1683-1-1.html
Arduino教程(提高篇)——把arduino变成AVRISP烧写器 http://www.arduino.cn/thread-1245-1-1.html
Arduino教程(提高篇)——红外遥控控制舵机 http://www.arduino.cn/thread-1242-1-1.html
Arduino教程(提高篇)——使用Ethernet构建简易的Web Server http://www.arduino.cn/thread-8514-1-1.html
在Arduino中使用看门狗定时器 http://www.arduino.cn/thread-2638-1-1.html
串口的高级用法 http://www.arduino.cn/thread-2710-1-1.html
修改Arduino串口缓冲区大小 http://www.arduino.cn/thread-7885-1-1.html
在Arduino上使用printf格式化输出到串口 http://www.arduino.cn/thread-8366-1-1.html
4.各种传感器、模块使用
传感器扩展板的使用 http://www.arduino.cn/thread-2779-1-1.html
五向倾斜模块 http://www.arduino.cn/thread-2327-1-1.html
旋转编码器 http://www.arduino.cn/thread-2423-1-1.html
无源蜂鸣器模块 http://www.arduino.cn/thread-1513-1-1.html
DS18B20温度传感器 http://www.arduino.cn/thread-1345-1-1.html
DHT11温湿度传感器 http://www.arduino.cn/thread-1429-1-2.html
LM35线性温度传感器 http://www.arduino.cn/thread-1055-1-1.html
韦根协议(26位)及其读取算法 http://www.arduino.cn/thread-2587-1-2.html
GSM/GPRS/GPS系列教程 http://www.arduino.cn/thread-6985-1-1.html
5.实例制作
基于Arduino的数字示波器 http://www.arduino.cn/thread-3703-1-1.html
模型用GPS测速仪 http://www.arduino.cn/thread-3623-1-1.html
Arduino实现自动浇水、遮阳 http://www.arduino.cn/thread-3437-1-1.html
基于arduino 控制的语音控制调节台灯 http://www.arduino.cn/thread-3520-1-1.html
智能壁障小车(带控制端) http://www.arduino.cn/thread-3445-1-1.html
Arduino制作自行车POV制作 http://www.arduino.cn/thread-3748-1-1.html
远程遥控侦查机器人 http://www.arduino.cn/thread-3768-1-1.html
基于Arduino的穿戴式LED灯条表演服 http://www.arduino.cn/thread-3400-1-1.html
Aduino 制作音乐播放器 http://www.arduino.cn/thread-2944-1-1.html
Arduino小车制作教程(巡线、壁障、遥控) http://www.arduino.cn/thread-3728-1-1.html
人工智能之五子棋机器人——人机对弈 http://www.arduino.cn/thread-1108-1-1.html
基于arduino控制器智能垃圾桶 http://www.arduino.cn/thread-975-1-1.html
Arduino 蓝牙遥控小车 http://www.arduino.cn/thread-2247-1-1.html
Ulink基于微信公众平台的远程物联网控制方案 http://www.arduino.cn/thread-7368-1-1.html
自平衡机器人——蛋黄物语 http://www.arduino.cn/thread-6246-1-1.html
艺术类项目——如影随形 http://www.arduino.cn/thread-7211-1-1.html
基于arduino的迈克尔逊干涉仪测量自动化装置 http://www.arduino.cn/thread-6220-1-1.html
6.Arduino Leonardo专题
Arduino Leonardo 中文介绍 http://www.arduino.cn/thread-1205-1-1.html
leonardo做的无线鼠标 http://www.arduino.cn/thread-2436-1-1.html
关于leonardo在模拟USB设备后,无法下载的问题 http://www.arduino.cn/thread-1653-1-1.html
7.Arduino Due专题
Arduino Due 中文介绍 http://www.arduino.cn/thread-2216-1-1.html
第三方CANBUS库 http://www.arduino.cn/thread-5735-1-1.html
8.Arduino Yun专题
Arduino Yun 中文介绍 http://www.arduino.cn/thread-4075-1-1.html
9.Arduino Zero专题
Arduino Zero 中文介绍
10.Arduino Ethernet专题
Arduino Ethernet中文介绍 http://www.arduino.cn/thread-8384-1-1.html
11.Intel Galileo/Edison专题
Intel Galileo/Edison资源汇总贴 http://www.arduino.cn/thread-4526-1-1.html
X.其他
Yeelink-物联网跟我做 http://www.arduino.cn/thread-1142-1-1.html
arduino学习笔记 - Mega 2560+TFT3.2寸屏的演示实验 http://www.arduino.cn/thread-989-1-3.html
Arduino UNO + GP2D12红外测距传感器+LCD1602详细演示过程 http://www.arduino.cn/thread-1107-1-1.html
Arduino Uno + HY-SRF05 超声波测距模块详细讲解演示实验 http://www.arduino.cn/thread-1110-1-1.html
arduino学习笔记 - Arduino Uno + MMA7361三轴加速度传感器 http://www.arduino.cn/thread-1141-1-1.html
AVR学习
AVRGCC用户手册 http://www.arduino.cn/avrgcc/
Arduino示例教程模块版汇总
1、Arduino示例教程模块版——开始您的Aduino之旅(WINDOWS版)
2、Arduino示例教程模块版——传感器扩展板的使用
3、Arduino示例教程模块版——按键实验
4、Arduino示例教程模块版——模拟声控路灯实验
5、Arduino示例教程模块版——直滑电位器与光互动实验
6、Arduino示例教程模块版——数字抢答器实验
7、Arduino示例教程模块版——超声波测距实验
8、Arduino示例教程模块版——红外遥控实验
9、Arduino示例教程模块版——舵机控制实验
10、Arduino示例教程模块版——人体红外报警实验
11、Arduino示例教程模块版——避障传感器与光互动实验
12、Arduino示例教程模块版——电子琴实验
13、Arduino示例教程模块版——智能环境监控实验
Cooper Maa系列教程汇总贴
使用者可以在 Arduino 板子上接上各種電子裝置,例如 LED 燈、喇叭、馬達、開關、溫濕度感測器、紅外線發射與接收器、LCD 顯示裝置,以及 Ethernet, WiFi, XBee, Bluetooth, RFID, GPS 等各種通訊模組。若再配合撰寫一些自動控制的程式,就能利用 Arduino 做出各式各樣的自動控制應用,例如利用溫度感測器控制風扇的運轉、使用可變電阻控制燈光的明暗、控制馬達的轉速、利用紅外線遙控家電/ 利用伺服機 (Servo) 控制機械手臂或機器人,以及製作自走車、飛行器等等。
這系列教學將讓你認識 Arduino,並且向你介紹各種基本電子裝置的使用方法。
教學目標
學習撰寫 Arduino 程式,以及使用各種基本電子裝置,包括: LED, 蜂鳴器、觸動開關、可變電阻、PWM 調光器、光敏電阻、七段顯示器、字元 LCD、74HC595 移位暫存器、Matrix LED、Keypad、伺服馬達、紅外線移動感測器、紅外線測距以及繼電器等。
授課對象
Arduino 進入門檻低,即便你沒有電子電機相關科系的背景,也可以很容易學會使用 Arduino,因此只要具備基本電腦操作能力就可以學習。
认识 Arduino http://www.arduino.cn/thread-2815-1-1.html
准备开发环境 http://www.arduino.cn/thread-2823-1-1.html
Lab1 Blinking a LED http://www.arduino.cn/thread-2853-1-1.html
Lab2 使用按鍵控制 LED 燈號 http://www.arduino.cn/thread-2854-1-1.html
Lab3 控制 LED 灯亮度 http://www.arduino.cn/thread-2855-1-1.html
Lab4 使用电位器调光 http://www.arduino.cn/thread-2871-1-1.html
Lab5 LED Bar Graph http://www.arduino.cn/thread-2872-1-1.html
Lab6 控制蜂鸣器发声 http://www.arduino.cn/thread-2877-1-1.html
Lab7 使用七段顯示器製作倒數功能 http://www.arduino.cn/thread-2881-1-1.html
Lab8 使用光敏电阻控制 LED 的开关 http://www.arduino.cn/thread-2907-1-1.html
Lab9 在1602 LCD 上显示 "Hello World" http://www.arduino.cn/thread-2908-1-1.html
Lab10 使用 SHT15 溫溼度計 http://www.arduino.cn/thread-2913-1-1.html
實例介紹:只做一个Arduino温度记录器(三部曲) http://www.arduino.cn/thread-2928-1-1.html
http://www.arduino.cn/thread-2929-1-1.html
http://www.arduino.cn/thread-2930-1-1.html
Lab11 使用 74HC595 和三支腳位控制 8 个LED http://www.arduino.cn/thread-3006-1-1.html
Lab12 使用兩顆 74HC595 和三支腳位控制 16个LED http://www.arduino.cn/thread-3007-1-1.html
Lab13 使用 74HC595 与7段数码管制作倒数功能 http://www.arduino.cn/thread-3010-1-1.html
Lab14 使用 74HC595 控制 HD44780 兼容 LCD http://www.arduino.cn/thread-3135-1-1.html
Lab15 使用四位七段数码管制作计数器 http://www.arduino.cn/thread-3140-1-1.html
Lab16 使用电位器控制舵机 http://www.arduino.cn/thread-3321-1-1.html
Lab17 使用光敏电阻控制舵机 http://www.arduino.cn/thread-3322-1-1.html
Lab18 讀取 3x4 Keypad 的輸入 http://www.arduino.cn/thread-3396-1-1.html
Lab19 使用 5x7 LED Matrix http://www.arduino.cn/thread-3397-1-1.html
Lab20 用紅外線動作感測器(PIR Motion Sensor)控制 LED 的開關 http://www.arduino.cn/thread-3398-1-1.html
Lab21 用繼電器控制 12V 風扇 http://www.arduino.cn/thread-3399-1-1.html
java - Why is TimeZone.getTimeZone(id) synchronized, and why this isn't documented? - Stack Overflow
有JavaEE系统一个服务器实例耗尽32核CPU,看到有大量如下线程堆栈信息:
"[ACTIVE] ExecuteThread: '255' for queue: 'weblogic.kernel.Default (self-tuning)'" daemon prio=10 tid=0x00002aaad2ba8000 nid=0x247f waiting for monitor entry [0x00002aaaefa37000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.util.TimeZone.getDefaultInAppContext(TimeZone.java:627)
- locked <0x00000006e05a43e8> (a java.lang.Class for java.util.TimeZone)
at java.util.TimeZone.getDefaultRef(TimeZone.java:523)
at java.util.GregorianCalendar.<init>(GregorianCalendar.java:541)
at com.aspire.mo.framework.util.DateUtil.getCacheDate(DateUtil.java:292)
at com.itindex.mo.framework.base.QueryTemplate$2.query(QueryTemplate.java:279)
上面这个锁导致了50多个线程被阻塞。
分析:在使用大量内存的大型多线程环境中,TimeZone是一个瓶颈,它使用了一个 synchronized HashMap。
建议:使用Joda-Time时间类来代替Calendar类消除这个瓶颈。
参见下列Java 日期类性能测试:
I tested single threaded performance, where 1M Dates were created using each method in a single thread. Then multi-threaded with 4 threads, each thread creating 250k Dates. In other words: both methods ended up creating the same number of Dates.
看到Calendar日期类性能最差。
参考:
http://blog.lick-me.org/2013/08/java-date-performance-subtleties/