本案例出于《深入理解Java虚拟机》第二版
场景
- 一个数字校园应用系统,运行在一台4个CPU的Solaris操作系统上,中间件为GlassFish服务器。
- 系统在做大并发压力测试的时候,发现请求响应时间比较慢,通过操作系统的mpstat工具发现CPU使用率很高,并且系统占用绝大多数的CPU资源的程序并不是应用系统本身。
- 这是一个不正常的现象,通常情况下用户应用的CPU占用率应该占据主要地位,才能说明系统是正常工作的。
问题
- 通过Solaris10的Dtrace脚本可以查看当前情况下哪些系统调用花费最多的CPU资源,Dtrace运行后发现最消耗CPU的是“fork”系统调用。
- “fork”系统调用是Linux用来产生新进程的,在Java虚拟机中,用户编写的Java代码最多只有线程的概念,不应当有进程的产生。
分析
- 这是非常异常的现象。找到原因:每个用户请求的处理都需要执行一个外部shell脚本来获得系统的一些信息。执行这个shell脚本是通过Java的Runtime.getRuntime().exec()方法来调用的。
- 这种调用方式可以达到目的,但是它在Java虚拟机中是非常消耗资源的操作,即使外部命令本身能很快执行完毕,频繁调用时创建进程的开销也非常可观。
- Java虚拟机执行这个命令的过程是:首先克隆一个和当前虚拟机拥有一样环境变量的进程,再用这个新的进程去执行外部命令,最后再退出这个进程。如果频繁执行这个操作,系统的消耗会很大,不仅是CPU,内存负担也很重。
解决方案
建议去掉这个Shell脚本执行的语句,改为使用Java的API去获取这些信息。
网友评论