Windows上的多线程Java应用程序的CPU使用率太低

Nil*_*ils 18 java java-native-interface multithreading jvm-hotspot numa

我正在开发一个Java应用程序,用于解决一类数值优化问题-更确切地说是大规模线性编程问题。单个问题可以分解为多个较小的子问题,这些子问题可以并行解决。由于子问题多于CPU内核,因此我使用ExecutorService并将每个子问题定义为可提交给ExecutorService的Callable。解决子问题需要调用本机库-在这种情况下为线性编程求解器。

问题

我可以在Unix和具有多达44个物理内核和256g内存的Windows系统上运行该应用程序,但是在Windows上,大问题的计算时间比Linux上高一个数量级。Windows不仅需要大量内存,而且随着时间的推移,CPU利用率从开始时的25%下降到几个小时后的5%。这是Windows中任务管理器的屏幕截图:

任务管理器CPU利用率

观察结果

  • 整个问题的大型实例的解决时间从数小时到数天不等,最多消耗32g的内存(在Unix上)。子问题的解决时间在ms范围内。
  • 对于仅需几分钟即可解决的小问题,我不会遇到此问题。
  • Linux开箱即用地使用了两个套接字,而Windows要求我显式地激活BIOS中的内存交错,以便应用程序利用两个内核。但是,是否执行此操作不会对总体CPU利用率随时间的下降造成影响。
  • 当我查看VisualVM中的线程时,所有池线程都在运行,没有一个正在等待。
  • 根据VisualVM,90%的CPU时间用于本机函数调用(解决一个小的线性程序)
  • 垃圾回收不是问题,因为该应用程序不会创建和取消引用很多对象。而且,大多数内存似乎是堆外分配的。对于最大实例,Linux上4g的堆足够,而Windows上8g的堆就足够了。

我尝试过的

  • 各种JVM参数,高XMS,高元空间,UseNUMA标志和其他GC。
  • 不同的JVM(热点8、9、10、11)。
  • 不同线性编程求解器(CLP,Xpress,Cplex,Gurobi)的不同本机库。

问题

  • 是什么导致大量使用本地调用的大型多线程Java应用程序在Linux和Windows之间的性能差异?
  • 在实现方面有什么可以改变的,例如Windows,我是否应该避免使用会接收成千上万个Callable的ExecutorService来代替呢?

Sam*_*ton 0

听起来Windows正在将一些内存缓存到页面文件中,在一段时间没有被触及之后,这就是CPU受到磁盘速度瓶颈的原因

您可以使用 Process explorer 进行验证并检查缓存了多少内存