java 启动负载高_jvm启动cpu和负载高分析

Java进程启动时,CPU高是因为JVM加载并解析所有非反射类,导致磁盘到内存的二进制解析消耗大量CPU资源。类加载不仅包括实际使用,还涉及依赖关系。即使main函数未直接使用其他类,只要存在依赖,JVM也会加载。通过实验验证,仅保留main函数的打印语句,CPU占用降低。JVM在启动时使用多线程加载类。
摘要由CSDN通过智能技术生成

我们知道,java进程在启动的时候经常会看到cpu会跑到百分之一百多,如果同一台机器有很多个java进程在同一时刻启动,每个进程cpu都是百分之一百多。为什么java启动会这么耗费CPU时间呢

原因如下:

主要是和jvm加载类文件有关,jvm在启动的时候会装载并连接所有除反射以外的类,而class文件是二进制的文件,需要从磁盘加载到内存然后解析,这种解析是很耗费cpu的,那么class文件越多,cpu耗费就越高,这正好解释了为什么同样输出Hello world,不同程序cpu占用率差别很大。这个推论正好也解释了之前遇到的另外一个线上项目的现象:每次启动后有大约1分钟左右系统的cpu和负载很高,过了1分钟后就恢复正常了

那么java虚拟机都是按需加载类的,那么我的main函数里面完全没有用到任何其它类,为何还是会加载呢?

今天针对这个问题继续查阅相关资料,发现原来所谓的“使用”,并不单单指我们通常编码所说看到的new、方法调用,而且还包括“依赖”。

举个简单的例子

packagecommon;import java.util.*;public classCommonTester {public static voidmain(String[] args) {

System.out.println("Hello, world......");

}/*** 这个函数在main里面并没有调用,但jvm还是会加载ArrayList类,因为CommonTester内依赖了ArrayList类

*@return

*/

public ListcreateStringList(){return new ArrayList(100);

}

}

以上这个例子中,CommonTester类在main函数中并没有调用crateStringList方法,但因为CommonTester类依赖ArrayList类,那么在加载CommonTester的时候发现其依赖ArrayList类,就会先加载ArrayList类。

所以,jvm最开始启动的时候肯定是先加载main函数所在的类,但是在加载这个类的时候发现依赖其它类,就会先加载其它类;加载其它类的时候也是这样处理,就像一个链式反应一样,所以基本上除了反射的类外,大部分类在jvm启动后,运行main函数前就已经加载完毕了。

为了验证这个推论,重新做了验证:

1)main函数所在的类注释所有其它代码,只保留main函数里面的打印语句

验证结果:cpu占用和自己写的简单的hello world程序一样,占用率大约1%左右

2)main函数所在的类注释所有其它代码,但保留import语句和main函数里面的打印语句

验证结果:和上面的一样,这个也很好理解,只保留import语句,因为这些语句并没有用,编译的时候这些语句都被优化掉了

jvm加载类的时候是多线程还是单线程 ?

验证这个问题流程如下

1)使用java -verbose启动程序,这样程序运行时就会打印加载的类

2)使用strace跟踪,就可以知道哪些线程加载了类

具体的命令为:strace -T -f -q -s 1024 -o strace.txt java -verbose .............(省略号代表具体的程序运行相关参数)

通过查看strace输出的结果,发现如下现象:

1)多个线程都会去加载类

2)同一线程需要用到的类如果还没有加载,则自己会去加载,不会再委托给其它线程加载

所以结论是jvm是通过多线程去加载类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值