分类目录归档:java

java入门与提高::::::演道网java专栏提供一线java研发人员在学习工作中的经验,减少大家走的弯路,大量源码可以直接使用。

一次Java调用OS命令的优化过程实录

<

div id=”content” contentScore=”3729″>

1前言

1.1优化目标

人脸识别(FaceRecognition)服务运行在Windows系统的bat文件中,其计算量非常大,运行耗时也比较长(10-20小时),并且在Java程序中使用Runtime执行命令,比直接运行cmd命令耗时更多,因此必须采取必要的手段对整个Server进行优化。

主要优化目标是降低Java程序中的执行时间,以提高吞吐率。

————————————–分割线 ————————————–

编写高质量代码 改善Java程序的151个建议 PDF高清完整版 http://www.linuxidc.com/Linux/2014-06/103388.htm

Java 8简明教程 http://www.linuxidc.com/Linux/2014-03/98754.htm

Java对象初始化顺序的简单验证 http://www.linuxidc.com/Linux/2014-02/96220.htm

Java对象值传递和对象传递的总结 http://www.linuxidc.com/Linux/2012-12/76692.htm

Java对象序列化ObjectOutputStream和ObjectInputStream示例 http://www.linuxidc.com/Linux/2012-08/68360.htm

————————————–分割线 ————————————–

1.2系统环境

1.2.1硬件环境

Server类型 虚拟机
CPU 1核,Intel(R) Xeon(R) CPU E5603 @ 1.60GHz
内存 3GB

1.2.2软件环境

操作系统 Windows XP Pro Version 2002 SP3
Tomcat apache-tomcat-7.0.47-windows-x86
JDK jdk1.7.0_04

1.3潜在优化点分析

下面,搭建模拟环境,分析潜在的优化点。

1.3.1加大Java VM内存

加内存,catalina.bat中加上Java VM参数:

set JAVA_OPTS=-Xms1024m -Xmx1024m -XX:PermSize=128M -XX:MaxPermSize=256m

下面是Tomcat添加JVM参数之后的对比结果(测试ffmpeg命令):

默认内存(64M 85 s
加大内存(1024M 85 s

可见,优化内存,基本无效。

1.3.2优化执行命令的Java方法

仍然采用上面的测试例子,不同方法的执行时间对比如下:

命令行中直接执行bat文件 69s
使用RunTime,不加cmd /c start 104s
使用RunTime,加cmd /c start,内存为64M 85s
使用RunTime,加cmd /c start,内存加大到512M 85s
使用processBuilder,不加cmd /c start 88s
使用processBuilder,加cmd /c start 87s
使用processBuilder,加cmd /c 87s

 

优化后,运行时间提升幅度为(104-85/104*100%=18.27%

1.3.3屏蔽输出

直接执行,输出信息 80s
直接执行,不输出信息 72s

 

优化后,运行时间提升幅度为(80-72/80*100%=10%

1.3.4CPU优化

12.4GHz 292s
42.5GHz 69s

 

优化后,运行时间提升幅度为(292-69/292*100%=76.37%

1.3.5Java Runtime优化

Java程序中使用Runtime执行操作系统命令的时候,发现java程序的CPU占用率高达66%,而执行的命令程序只占33%,因此需要考虑优化Runtime方法的执行。

优化方法:将执行命令的方法中启动的两个用于读取输出和错误流的线程去掉,改为直接读取这两个流,而不是启动2个线程。

优化前后对比如下:

测试项 优化前 优化后
Linux 直接在cmd中执行耗时 347s 344s
Java中使用Runtime执行耗时 728s 353s
CPU占用率 ffmpeg33%

Javaw66%

ffmpeg66%

Javaw33%

Windows 直接在cmd中执行耗时 87s 86s
Java中使用Runtime执行耗时 107s 88s
CPU占用率 ffmpeg20%

Javaw40%

ffmpeg40%

Javaw0%

 

优化后,运行时间提升到和直接执行命令相当的水平。

2优化过程

*搭建测试环境

*记录命令行上的执行时间;

*记录Java程序中的执行时间;

*按照优化点分析进行优化,分别记录优化之后的执行时间;

*生成优化报告,并记录详细的优化步骤,供后续使用。

2.1搭建测试环境

1)搭建人脸识别的运行环境。

2)由于人脸识别步骤耗时较长,为了便于快速进行优化测试,准备一个24秒长的电影片段,总共包含4个人脸,并且每一帧都会有至少一个人脸。

2.2在命令行中执行

CMD中执行下面的命令,以手动启动人脸检测步骤。

C:Face.bat Y:FaceRecognitionDispatcherMoviesface.avi

记录命令执行前后的时间如下:

The current time is: 18:11:04.52

The current time is: 18:19:29.09

总计执行504秒。

2.3Java程序中执行

Java程序中采用“Runtime.getRuntime().exec(cmd)”的方式执行Windows操作系统的DOS命令,其中命令前面加上“cmd /c start”参数,以提高执行效率。

记录命令执行前后的时间如下:

The current time is: 13:54:15

The current time is: 14:21:12

总计执行1617秒。

2.4性能优化

2.4.1内存优化

将默认的64M内存加大为1024M。在catalina.bat中加上Java VM参数:

set JAVA_OPTS=-Xms1024m -Xmx1024m -XX:PermSize=128M -XX:MaxPermSize=256m

记录命令执行前后的时间如下:

The current time is: 14:27:23

The current time is: 14:50:18

总计执行1375秒。

2.4.2屏蔽输出

将人脸识别bat文件中输出全部屏蔽掉,在bat文件中每个命令的后面加上“> nul”参数。

记录命令执行前后的时间如下:

The current time is: 15:17:09

The current time is: 15:39:15

总计执行1326秒。

2.4.3CPU优化

*只增加CPU数量,不增加CPU主频

将原来的1CPU扩展到8CPUCPU配置为:Intel(R) Xeon(R) CPU E5603 @ 1.60GHz

记录命令执行前后的时间如下:

The current time is: 21:51:55

The current time is: 22:00:38

总计执行523秒。

*既增加CPU数量,又增加CPU主频

将原来的1CPU扩展到32CPUCPU配置由1.60GHz变为2.13GHz

记录命令执行前后的时间如下:

The current time is: 10:35:07

The current time is: 10:41:21

总计执行374秒。

2.4.4Java Runtime优化

优化前后对比如下:

测试项 优化前 优化后
直接在cmd中执行 245s 245s
Java中使用Runtime执行 374s 239s

 

优化后,运行时间提升到和直接执行命令相当的水平。

更夼/div>

Java动态绑定的内部实现机制

<

div id=”content” contentScore=”2413″>Java虚拟机调用一个类方法时,它会基于对象引用的类型(通常在编译时可知)来选择所调用的方法。相反,当虚拟机调用一个实例方法时,它会基于对象实际的类型(只能在运行时得知)来选择所调用的方法,这就是动态绑定,是多态的一种。动态绑定为解决实际的业务问题提供了很大的灵活性,是一种非常优美的机制。

1 Java对象模型

Java虚拟机规范并没有规定Java对象在堆里是如何表示的。对象的内部表示也影响着整个堆以及垃圾收集器的设计,它由虚拟机的实现者决定。

Java对象中包含的基本数据由它所属的类及其所有超类声明的实例变量组成。只要有一个对象引用,虚拟机就必须能够快速地定位对象实例的数据。另外,它也必须能通过该对象引用访问相应的类数据(存储于方法区的类型信息),因此在对象中通常会有一个指向方法区的指针。当程序在运行时需要转换某个对象引用为另外一种类型时,虚拟机必须要检查这种转换是否被允许,被转换的对象是否的确是被引用的对象或者它的超类型。当程序在执行instanceof操作时,虚拟机也进行了同样的检查。所以虚拟机都需要查看被引用的对象的类数据。

不管虚拟机的实现使用什么样的对象表示法,很可能每个对象都有一个方法表因为方法表加快了调用实例方法时的效率。但是Java虚拟机规范并未要求必须使用方法表,所以并不是所有实现中都会使用它。

下面是一种Java对象的内存表示:

Java对象内存模型 

方法数据存放在类的方法区中,包含一个方法的具体实现的字节码二进制。方法指针直接指向这个方法在内存中的起始位置,通过方法指针就可以找到这个方法。

2 动态绑定内部机制

方法表是一个指向方法区中的方法指针的数组。方法表中不包含static、private等静态绑定的方法,仅仅包含那些需要动态绑定的实例方法。

在方法表中,来自超类的方法出现在来自子类的方法之前,并且排列方法指针的顺序和方法在class文件中出现的顺序相同,这种排列顺序的例外情况是,被子类的方法覆盖的方法出现在超类中该方法第一次出现的地方。

例如有超类Base和子类Derive:

<

ol>

  • public class Base    
  • {   
  •   public Base()   
  •   {   
  •   }   
  •       
  •   public void test()   
  •   {   
  •     System.out.println( “int Base” );   
  •   }   
  •      
  •   public void print()   
  •   {   
  •   }   
  • }   
  •   
  • public class Derive extends Base   
  • {   
  •   public Derive()   
  •   {   
  •   }   
  •   
  •   public void test()   
  •   {   
  •     System.out.println( “int Derive” );   
  •   }   
  •      
  •   public void sayHello()   
  •   {   
  •   }   
  •      
  •   public static void main( String[] args )   
  •   {   
  •       Base base = new</strong