JNI初探踩坑

源于编程之美第一道题控制CPU,顺利用java把50%和sin线都画完之后(得把其他进程都关了,还得根据自己电脑核数创建相应线程数),该书提出C++直接监控当前windows系统的CPU占用率,动态的保持系统CPU占用率在50%。然后我就开始头疼了,没听说java这种跨平台的虚拟机上的语言有直接的接口查看操作系统的CPU信息啊,查找了各种资料。

写了如下代码进行测试:

package useRateOfCpu1_1;
import java.lang.management.ManagementFactory;

import com.sun.management.OperatingSystemMXBean;
public class Test{
	public static void main(String[] args) {
		OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
		// What % CPU load this current JVM is taking, from 0.0-1.0
		System.out.println(osBean.getProcessCpuLoad());//指CPU的负载情况
		while(true) {
			System.out.println(osBean.getProcessCpuLoad());
			if(osBean.getProcessCpuLoad() > 0.5) {
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
			}
		}
		

	}
}

发现占有率一直是25%左右。。
查看官方文档:double getSystemCpuLoad() Returns the “recent cpu usage” for the whole system.
又在资源监视器里监视了运行后的进程,发现打印出的值跟该进程占的CPU相同,跟整个windows系统CPU占有率没啥关系。。。

  • 二探,Sigar,开源工具肯定是第二个目标呀~
    https://blog.csdn.net/HarderXin/article/details/76849884
    https://github.com/hyperic/sigar
    一个用C语言写的可供java调用的基本上能够获取操作系统的全部信息的包,刚找到的时候很兴奋,结果调了半天,最后eclipse给我报了一个JVM崩溃的错,google了半天,应该是java10或者win10版本兼容问题。。又不能用。。

  • 三探,JNI,没办法了就看java提供了有什么能解决该问题的功能没 = 。=
    这也就是今天的主题了,Java Native Interface,Java本地接口。JNI使得我们可以在JAVA中调用本地的C++代码(C++忘完了快),非常强大!

由于一些涉及到设备或底层操作的类库,大多是C或C++语言编写的,在涉及到相应的项目中,不可能再去将相应的类库用Java重写。这时,就需要通过Java代码去调用C/C++的类库来完成工作。

整个流程简单说就是:
写个java接口–>编译–>生成一个.h文件(java来生成的,所以jni才能用)–>根据.h文件把.cpp文件写出来,实现功能–>生成.dll动态链接库并放进classpath–>java文件调用接口完成功能
下面详细解释下各个部分,以及我踩的一些坑。
代码参考了 https://github.com/rootsu1024x/GetCPUMemNetOnJava

编写java接口

package net.caffeineswitch.lib.getcmn;

public class CPU {
	static{
		if("x86".equals(System.getProperty("os.arch"))){
			System.loadLibrary("CPUUsage");
		}else if("amd64".equals(System.getProperty("os.arch"))){
			System.loadLibrary("TestJ");
		}
	}

	public native double getCPUUsage();

	public CPU() {
	}
}

编写完成后javac编译成.class文件

生成.h头文件

这里很坑,查到的资料都让对上一步生成的.class文件利用jdk的javah命令来生成.h头文件。结果发现网上一些教程使用的方法(javah -jni 目标文件)已经过时,这是因为java10已经移除了javah的相关功能。
java10可以用来生成.h头文件

javac -h . CPU.java //注意h和C中间的“.”

生成的.h文件回事 包路径+类名

编写C++代码,生成dll文件

我为了图快直接VS2010写的,创建一个dll项目,注意要是x64平台的,这些坑大学期间踩过就明白有多烦人了,然后注意,要把你自己的jdk里的jni.h(jdk/include)和jni_md.h(jdk/include/win32),还有上面那个生成的.h文件都放进C++项目的头文件里,然后自己添加一个cpp文件,把功能实现了,这里就只是查看一下系统CPU,用的是windows自带的一个库,也是C++里自带的库Performance Data Helper (PDH),性能数据助手,可以根据 https://blog.csdn.net/fengyishang/article/details/46440135 一文把功能完成。这里就不细讲了。
之前没写过dll项目,编译的时候给我报错说不能运行,我以为一直有bug,结果查了下才发现自己太傻了,只生成个dll当然没有东西可以运行。去debug里一找,果然dll文件已经有了。

java链接进生成的dll文件

最简单的直接把dll放到jdk环境里面,然后就可以在java文件中使用了。

package net.caffeineswitch.lib.getcmn;

public class TestMain {
	public static void main(String[] args) {
		System.out.println(System.getProperty("os.arch"));

		CPU cpu = new CPU();
		
		while(true){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("CPU:"+cpu.getCPUUsage());
			
		}
	}

}

最后查了一下,跟任务管理器资源监视器里的CPU占用率还是有点不一样,不管怎么说,之前看到JNI、Sigar这些乱七八糟的词心里都慌慌的,觉得有好多东西要学,其实真的花了一个下午把这些没接触过的东西接触一遍,踩踩坑,发现其实也就是那么回事。
毕竟编程就是一个发现问题,找工具,解决问题的过程。

猜你喜欢

转载自blog.csdn.net/u013453787/article/details/83865169
今日推荐