【IT168技术文档】概述
在开发中,性能测试是设计初期容易忽略的问题,开发人员会为了解决一个问题而“不择手段”,作者所参与的项目中也遇到了类似问题,字符串拼接、大量的网
络调用和数据库访问等等都对系统的性能产生了影响,可是大家不会关心这些问题,“CPU速度在变快”,“内存在变大”,并且,“好像也没有那么慢吧”。
有很多商业的性能测试软件可供使用,如Jprofiler、JProbe Profiler等,但在开发当中显得有些遥远而又昂贵。
2 目标
本文将讲述如何利用Java语言本身提供的方法在开发中进行性能测试,找到系统瓶颈,进而改进设计;并且在尽量不修改测试对象的情况下进行测试。
3 预备知识
面向对象编程通过抽象继承采用模块化的思想来求解问题域,但是模块化不能很好的解决所有问题。有时,这些问题可能在多个模块中都出现,像日志功能,为了
记录每个方法进入和离开时的信息,你不得不在每个方法里添加log("in some
method")等信息。如何解决这类问题呢?将这些解决问题的功能点散落在多个模块中会使冗余增大,并且当很多个功能点出现在一个模块中时,代码变的
很难维护。因此,AOP(Aspect Oriented Programming)应运而生。如果说OOP(Aobject Oriented
Programming)关注的是一个类的垂直结构,那么AOP是从水平角度来看待问题。
动态代理类可以在运行时实现若干接口,每一个动态代理类都有一个Invocation
handler对象与之对应,这个对象实现了InvocationHandler接口,通过动态代理的接口对动态代理对象的方法调用会转而调用
Invocation handler对象的invoke方法,通过动态代理实例、方法对象和参数对象可以执行调用并返回结果。
说到AOP,大家首先会想到的是日志记录、权限检查和事务管理,是的,AOP是解决这些问题的好办法。本文根据AOP的思想,通过动态代理来解决一类新的问题——性能测试(performance testing)。
性能测试主要包括以下几个方面:
l 计算性能:可能是人们首先关心的,简单的说就是执行一段代码所用的时间
l 内存消耗:程序运行所占用的内存大小
l 启动时间:从你启动程序到程序正常运行的时间
l 可伸缩性(scalability)
l 用户察觉性能(perceived performance):不是程序实际运行有多快,而是用户感觉程序运行有多快.
本文主要给出了计算性能测试和内存消耗测试的可行办法。
4 计算性能测试
4.1 目标:
通过该测试可以得到一个方法执行需要的时间
4.2实现:
Java为我们提供了System. currentTimeMillis()方法,可以得到毫秒级的当前时间,我们在以前的程序当中一定也写过类似的代码来计算执行某一段代码所消耗的时间。
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->long
start
=
System.currentTimeMillis();
doSth();
long
end
=
System.currentTimeMillis();
System.
out
.println(
"
time lasts
"
+
(end
-
start)
+
"
ms
"
);
但是,在每个方法里面都写上这么一段代码是一件很枯燥的事情,我们通过Java的java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler利用动态代理来很好的解决上面的问题。
我们要测试的例子是java.util.LinkedList和java.util.ArrayList的get(int index)方法,显然ArrayList要比LinkedList高效,因为前者是随机访问,而后者需要顺序访问。
首先我们创建一个接口
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->public
interface
Foo {
public
void
testArrayList();
public
void
testLinkedList();
}
然后我们创建测试对象实现这个接口
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->public
class
FooImpl implements Foo {
private
List link
=
new
LinkedList();
private
List array
=
new
ArrayList();
public
FooImpl() {
for
(
int
i
=
0
;i
<
10000
;i
++
) {
array.add(
new
Integer(i));
link.add(
new
Integer(i));
}
}
public
void
testArrayList() {
for
(
int
i
=
0
;i
<
10000
;i
++
)
array.
get
(i);
}
public
void
testLinkedList() {
for
(
int
i
=
0
;i
<
10000
;i
++
)
link.
get
(i);
}
}
接下来我们要做关键的一步,实现InvocationHandler接口
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.
*
;
public
class
Handler implements InvocationHandler {
private
Object obj;
public
Handler(Object obj) {
this
.obj
=
obj;
}
public
static
Object newInstance(Object obj) {
Object result
=
Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new
Handler(obj));
return
(result);
}
public
Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
try
{
System.
out
.print(
"
begin method
"
+
method.getName()
+
"
(
"
);
for
(
int
i
=
0
; args
!=
null
&&
i
<
args.length; i
++
) {
if
(i
>
0
) System.
out
.print(
"
,
"
);
System.
out
.print(
"
"
+
args[i].toString());
}
System.
out
.println(
"
)
"
);
long
start
=
System.currentTimeMillis();
result
=
method.invoke(obj, args);
long
end
=
System.currentTimeMillis();
System.
out
.println(
"
the method
"
+
method.getName()
+
"
lasts
"
+
(end
-
start)
+
"
ms
"
);
}
catch
(InvocationTargetException e) {
throw
e.getTargetException();
}
catch
(Exception e) {
throw
new
RuntimeException(
"
unexpected invocation exception:
"
+
e.getMessage());
}
finally
{
System.
out
.println(
"
end method
"
+
method.getName());
}
return
result;
}
}
最后,我们创建测试客户端,
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->public
class
TestProxy {
public
static
void
main(String[] args) {
try
{
Foo foo
=
(Foo) Handler.newInstance(
new
FooImpl());
foo.testArrayList();
foo.testLinkedList();
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
运行的结果如下:
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->begin method testArrayList( )
the method testArrayList lasts 0ms
end method testArrayList
begin method testLinkedList( )
the method testLinkedList lasts 219ms
end method testLinkedList
使用动态代理的好处是你不必修改原有代码FooImpl,但是一个缺点是你不得不写一个接口,如果你的类原来没有实现接口的话。
4.3扩展
在上面的例子中演示了利用动态代理比较两个方法的执行时间,有时候通过一次简单的测试进行比较是片面的,因此可以进行多次执行测试对象,从而计算出最差、最好和平均性能。这样,我们才能“加快经常执行的程序的速度,尽量少调用速度慢的程序”。
5 内存消耗测试
5.1 目标
当一个java应用程序运行时,有很多需要消耗内存的因素存在,像对象、加载类、线程等。在这里只考虑程序中的对象所消耗的虚拟机堆空间,这样我们就可以利用Runtime 类的freeMemory()和totalMemory()方法。
5.2 实现
为了方便期间,我们首先添加一个类计算当前内存消耗。
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->class
Memory {
public
static
long
used() {
long
total
=
Runtime.getRuntime().totalMemory();
long
free
=
Runtime.getRuntime().freeMemory();
return
(total
-
free);
}
}
然后修改Handler类的invoke()方法。
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->public
Object invoke(Object proxy, Method method, Object[] args) throws Throwable ...{
Object result;
try
...{
System.
out
.print(
"
begin method
"
+
method.getName()
+
"
(
"
);
for
(
int
i
=
0
; args
!=
null
&&
i
<
args.length; i
++
) ...{
if
(i
>
0
) System.
out
.print(
"
,
"
);
System.
out
.print(
"
"
+
args[i].toString());
}
System.
out
.println(
"
)
"
);
long
start
=
Memory.used();
result
=
method.invoke(obj, args);
long
end
=
Memory.used();
System.
out
.println(
"
memory increased by
"
+
(end
-
start)
+
"
bytes
"
);
}
catch
(InvocationTargetException e) ...{
throw
e.getTargetException();
}
catch
(Exception e) ...{
throw
new
RuntimeException(
"
unexpected invocation exception:
"
+
e.getMessage());
}
finally
...{
System.
out
.println(
"
end method
"
+
method.getName());
}
return
result;
}
同时我们的测试用例也做了一下改动,测试同样一个显而易见的问题,比较一个长度为1000的ArrayList和HashMap所占空间的大小,接口、实现如下:
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->public
interface
MemoConsumer {
public
void
creatArray();
public
void
creatHashMap();
}
public
class
MemoConsumerImpl implements MemoConsumer {
ArrayList arr
=
null
;
HashMap hash
=
null
;
public
void
creatArray() {
arr
=
new
ArrayList(
1000
);
}
public
void
creatHashMap() {
hash
=
new
HashMap(
1000
);
}
}
测试客户端代码如下:
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->MemoConsumer arrayMemo
=
(MemoConsumer)Handler.newInstance(
new
MemoConsumerImpl ());
arrayMemo.creatArray();
arrayMemo.creatHashMap();
测试结果如下:
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->begin method creatArray( )
memory increased by 4400bytes
end method creatArray
begin method creatHashMap( )
memory increased by 4480bytes
end method creatHashMap
结果一幕了然,可以看到,我们只需要修改invoke()方法,然后简单执行客户端调用就可以了。
6 结束语
AOP
通过分解关注点和OOP相得益彰,使程序更加简洁易懂,通过Java语言本身提供的动态代理帮助我们很容易分解关注点,取得了较好的效果。不过测试对象必
须实现接口在一定程度上限制了动态代理的使用,可以借鉴Spring中使用的CGlib来为没有实现任何接口的类创建动态代理。
转载来源:http://tech.it168.com/j/2007-06-12/200706121625875.shtml
分享到:
相关推荐
根据提供的文件信息,我们可以推断出这是一本关于Java程序性能优化的书籍,作者是葛一鸣,并提供了该书PDF版本的下载链接。虽然没有具体的书籍内容,但基于标题、描述以及通常这类书籍会涉及的主题,我们可以总结出...
Java程序性能优化是每个开发人员都需要关注的重要领域,特别是在企业级应用中,高效稳定的Java程序能够显著提升用户体验,降低服务器资源消耗。这本书“Java程序性能优化 让你的Java程序更快、更稳定”提供了深入的...
Java程序性能测试技术是检测Java程序性能的重要手段,传统的测试平台在测试过程中需要在程序段内加入标志程序,因此会引发各种各样的代码污染情况,导致程序运行性能测试受到明显的影响。 本文研究了Java程序优化的...
Java程序性能优化是开发者在构建高效、稳定应用时必须关注的重要方面。Java作为一种跨平台的编程语言,其性能可以通过多种手段进行提升,包括但不限于代码优化、JVM参数调优、垃圾回收机制理解以及并发处理等。 ...
【Java服务程序性能测试总结】 在软件开发过程中,性能测试是一项至关重要的环节,尤其是在Java服务程序的场景下,确保服务程序能承受高并发负载并保持高效稳定运行是开发者的重要任务。以下是对整个性能测试过程的...
《Java程序性能优化》是葛一鸣在2012年10月出版的第一版专著,这本书深入探讨了如何提升Java应用程序的运行效率和性能。在Java开发中,性能优化是一个关键领域,它涉及到代码的高效编写、内存管理、线程调度、数据库...
### Java反射性能测试分析 #### 引言 Java反射机制是Java编程语言中一个强大的特性,它允许程序在运行时动态地访问、检测和修改类、接口、字段和方法等对象。然而,反射操作通常会引入额外的开销,这在性能敏感的...
Java程序性能优化是每个开发人员都需要关注的重要领域,特别是在企业级应用中,高效的代码执行能够带来更好的用户体验,减少服务器资源的消耗,降低运营成本。本资料包“Java程序性能优化 让你的Java程序更快、更...
在完成项目后,就可以进行系统测试了,可以将以下性能指标,作为性能调优的标准,响应时间、吞吐量、计算机资源分配使用率、负载承受能力。 本教程结合 Java 应用开发的知识点,将内容分为七大模块,从上到下依次...
JAVA性能测试工具是IT行业中用于评估和优化JAVA应用程序性能的关键组件。这些工具旨在模拟真实世界的负载情况,帮助开发者识别和解决性能瓶颈,确保应用程序在高负载下仍能保持稳定和高效运行。以下是对几种主要JAVA...
Java性能测试对于手机用户和开发者而言至关重要,因为这直接影响到应用程序的运行效率和用户体验。Java,特别是J2ME(Java 2 Micro Edition),是许多移动设备上应用开发的基础,尤其是早期智能手机。J2ME适用于资源...
通过JNI,Java程序能够利用C/C++等本地代码的高效性,同时保持Java的可移植性。 【JFreeChart库】 JFreeChart是一个开源的Java图形库,用于创建高质量的图表。在本系统中,JFreeChart可能被用来将监控到的系统数据...
Java虚拟机是Java体系的核心组件,它可以解释和执行Java程序代码,提供了跨平台的能力。 Java软件性能测试方法 --------------------- Java软件性能测试可以分为两种:功能测试和性能测试。功能测试是为了验证Java...
在基于JPDA的Java软件性能测试中,JPDA平台可以帮助开发者快速地对Java程序的性能和稳定性进行检测和分析,从而提高软件的整体质量。 基于JPDA的Java软件性能测试可以通过JPDA平台来进行简化测试,提高认软件的性能...
Java程序设计基础是编程学习的重要领域,主要涵盖了Java语言的基础概念、语法结构和特性。Java是一种全面面向对象的编程语言,由Sun公司的James Gosling等人于1990年开发,最初命名为Oak,后来因互联网的兴起而更名...
在Java程序设计中,性能优化是一项至关重要的任务,它直接影响到应用程序的运行效率、资源消耗以及用户体验。本文将深入探讨三种常见的Java程序设计性能优化策略,以帮助开发者提高代码的执行速度和整体系统性能。 ...
在Java开发过程中,性能优化和安全漏洞检测是至关重要的环节。Java性能瓶颈可能导致系统响应变慢,用户体验下降,甚至可能导致服务器资源耗尽。而漏洞的存在则可能让系统面临被攻击的风险,因此,掌握有效的检测工具...
Java程序性能优化是每个开发人员都需要关注的重要领域,它直接影响到应用程序的运行效率、资源消耗以及用户满意度。本文将深入探讨如何通过各种技术手段提升Java程序的性能,并使其运行更加稳定。 1. **JVM调优** ...
1. **JVM参数调整**:Java虚拟机(JVM)是Java程序运行的基础,它的配置直接影响到程序性能。例如,可以通过设置-Xms和-Xmx调整堆内存大小,避免垃圾回收频繁;通过-XX:NewRatio控制新生代和老年代的比例,优化对象...