NIO在Windows下占用大量CPU资源原因详解

1. 现象简述

在项目性能测试过程中发现,同样的代码,连接同样数量(10万)的设备(设备和代码之间通过NIO有大量的数据交互),在Linux下CPU利用率只有20%~30%,而在windows下却一直高于80%。

2. 原因初步排查

通过jconsole分别监控运行在linux和windows上的程序,在【线程】选项卡中发现,windows下启动了大量未命名线程,堆栈信息都类似于下图:
在这里插入图片描述

通过Java自带的Jstack将Java程序对应进程的内存信息导出,命令如下:

jstack -l 31372 > c:/31372.stack  

说明: 其中31372为该进程的PID。

然后搜索有相同堆栈信息的线程,发现同样的线程启动了97个,通过windows的监控工具Process Explorer(该工具使用可参考这里)可以发现,这些线程每个大约占用0.7%~0.9%的CPU资源,那么这97个线程约占用了69.7%的CPU资源,而Linux并未启动这些线程,这也就可以从宏观上解释windows下CPU利用率比Linux高出60%多的现象了。

3. NIO深度分析

从openJDK下载WindowsSelectorImpl类的源码,可以发现:

final class WindowsSelectorImpl extends SelectorImpl {
    ...
}

该类继承了SelectorImpl类,于是找到SelectorImpl类的源码:

abstract class SelectorImpl extends AbstractSelector {
    ...
}

可以发现,该类继承了AbstractSelector抽象类。

在Eclipse中,可以看到这个类的继承关系:
在这里插入图片描述

即这些类最终的实现类为Selector,在代码中找到使用Selector类的地方:

int n = selector.select(25);

Selector类的select()方法在SelectorImpl类中实现,具体如下:

public int select(long timeout) throws IOException {
    if (timeout < 0)
        throw new IllegalArgumentException("Negative timeout");
    return lockAndDoSelect((timeout == 0) ? -1 : timeout);
}

select()方法调用了lockAndDoSelect()方法,源码如下:

private int lockAndDoSelect(long timeout) throws IOException {
    synchronized (this) {
        if (!isOpen())
            throw new ClosedSelectorException();
        synchronized (publicKeys) {
            synchronized (publicSelectedKeys) {
                return doSelect(timeout);
            }
        }
    }
}

lockAndDoSelect()方法调用了doSelect()方法,而doSelect()方法在SelectorImpl类中是抽象方法。

protected abstract int doSelect(long timeout) throws IOException;

其具体实现与操作系统相关,windwos系统中该方法在WindowsSelectorImpl类中实现,Linux系统中该类在EPollSelectorImpl类中实现。

3.1 Windows下NIO的实现分析

查看WindowsSelectorImpl类的源码,找到doSelect()方法,源码如下:

protected int doSelect(long timeout) throws IOException {
    if (channelArray == null)
        throw new ClosedSelectorException();
    this.timeout = timeout; // set selector timeout
    processDeregisterQueue();
    if (interruptTriggered) {
        resetWakeupSocket();
        
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值