- 浏览: 201509 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
brenda:
...
技术选型(转) -
JavaScriptOMG:
写的真好,不知道如果是java.sql.date的话,怎么写呢 ...
Java得到下一天明天,明天时间 -
少女杀手:
和他的一摸一样,一个字都不差
http://anysky131 ...
弹出窗口代码大全 -
shipping:
字体好小啊,都没兴趣看下去了
测试网站性能的30款免费在线工具 -
ddd:
其实一切人活着的意义就在于他死前的心情是什么。
活着是多么美好
Java程序性能测试
1 概述
在开发中,性能测试是设计初期容易忽略的问题,开发人员会为了解决一个问题而“不择手段”,作者所参与的项目中也遇到了类似问题,字符串拼接、大量的网络调用和数据库访问等等都对系统的性能产生了影响,可是大家不会关心这些问题,“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()方法,可以得到毫秒级的当前时间,我们在以前的程序当中一定也写过类似的代码来计算执行某一段代码所消耗的时间。
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高效,因为前者是随机访问,而后者需要顺序访问。
首先我们创建一个接口
public interface Foo { public void testArrayList(); public void testLinkedList(); } |
然后我们创建测试对象实现这个接口
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接口
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; } } |
最后,我们创建测试客户端,
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(); } } } |
运行的结果如下:
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 实现
为了方便期间,我们首先添加一个类计算当前内存消耗。
class Memory { public static long used() { long total=Runtime.getRuntime().totalMemory(); long free=Runtime.getRuntime().freeMemory(); return (total-free); } } |
然后修改Handler类的invoke()方法。
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所占空间的大小,接口、实现如下:
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); } } |
测试客户端代码如下:
MemoConsumer arrayMemo=(MemoConsumer)Handler.newInstance(new MemoConsumerImpl ()); arrayMemo.creatArray(); arrayMemo.creatHashMap(); |
测试结果如下:
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来为没有实现任何接口的类创建动态代理。
7 参考资料
本文中提到的一些性能测试概念主要来自http://java.sun.com/docs/books/performance/
一些AOP的概念来自Jboss的http://www.jboss.org/index.html?module=html&op=userdisplay&id=developers/projects/jboss/aop
动态代理和AOP的某些知识来自http://www.springframework.org/docs/reference/aop.html
8 作者声明
东西写的一般,不过是我辛勤劳动所为,转载请注明出处,可以通过whq3721@163.com 与我联系,http://freshman.52blog.net
发表评论
-
技术选型(转)
2011-05-17 15:05 11252.1. 基础架构 ... -
分布式Java 应用(转)
2011-05-17 14:43 1345网络通信:协议TCP/IP,UDP/Ip,Multicas ... -
跨域访问session(转)
2011-04-22 16:14 2638大一些的网站,通常都 ... -
(转)分享一下,我常去的中文技术网站
2011-04-18 13:31 837先说一下大多数人都知 ... -
(转) request.getPathInfo() 方法的作用
2011-04-14 11:58 886request.getPathInfo(); 这个方法返回请 ... -
需要牢记的java编程规则(收藏)
2011-04-10 20:52 728(1) 类名首字母应该 ... -
一个计算机专业学生几年的编程经验汇总之二(收藏)
2011-04-10 19:48 870############################### ... -
一个计算机专业学生几年的编程经验汇总之一(收藏)
2011-04-10 18:05 856来学习Java也有两个年头了,永远不敢说多么精通,但也想谈谈自 ... -
(转)各种架构图汇总
2011-04-06 22:27 1393转载请保留出处,刘晓涛汇总!!! http://bl ... -
(转)java并发编程实践笔记
2011-04-05 22:23 7711, 保证线程安全的三种方法 : a, 不要跨线程访问共享变量 ... -
(转)构建可伸缩,高性能的互联网应用
2011-04-05 22:22 755间过得很快,来新公司已经两个月了,在这两个月的时间里,自己也感 ... -
(转)百万级访问量网站的技术准备工作
2011-04-05 22:20 887当今从纯网站技术上来说,因为开源模式的发展,现在建一个小网站已 ... -
测试数据库连接状态
2011-03-25 08:45 1361while (true) { long star ... -
(转)什么是Java里的OO思想?
2011-03-24 14:12 886OO就是面向对象 面向对象(Object Oriented,O ... -
(转)JAVA 检测网络是否为连通状态 ping
2011-03-23 14:34 2509要用java检测网络资源是否可用,我们可以采用以下两种方法: ... -
中文乱码问题的解决方法
2011-01-21 17:33 1158tomcat下中文的彻底解决[转] http://blo ... -
nginx 映射80端口
2009-08-04 09:13 3878配置一个resin, 为不用输入端 ... -
调整 Java 虚拟机
2009-07-09 23:43 1018尽管 JVM 调整操作随 JVM 提供程序的不同而有所变化,但 ... -
测试网站性能的30款免费在线工具
2009-06-28 02:12 2008你是否肯定你的网站完全兼容各大浏览器?是否知道多少秒可以打开你 ... -
Memcached-----memcached实现内存缓存
2009-06-27 15:38 2696Memcached是danga.com(运营LiveJourn ...
相关推荐
Apache JMeter是一款纯java编写负载功能测试和性能测试开源工具软件。相比Loadrunner而言,...本文为JMeter性能测试完整入门篇,从Jmeter下载安装到编写一个完整性能测试脚本、最终执行性能测试并分析性能测试结果。
1.8 性能测试:mysql5.5与mysql5.1 60 第2章 半同步复制 62 2.1 半同步复制简介 62 2.2 半同步复制安装配置 63 2.3 参数说明 63 2.4 功能测试 64 2.4.1 如何验证半同步复制是否正常工作 64 2.4.2 半同步复制...
实用又安全的高性能之路就是通过复制来扩展你现有的应用系统,其中也包含了负载平衡、高可用性和故障恢复等技术。 第二版针对第一版作了彻底的修订,极大地扩充了原有内容,对所有领域进行了更深入的论述。新增的...
由国内著名技术社区联合推荐的2012年IT技术力作:《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》,即将上架发行,此书从Web应用、数据备份与恢复、网络存储应用、运维监控与性能优化、集群高级应用等...
实用又安全的高性能之路就是通过复制来扩展你现有的应用系统,其中也包含了负载平衡、高可用性和故障恢复等技术。 本书第二版针对第一版作了彻底的修订,极大地扩充了原有内容,对所有领域进行了更深入的论述。...
目录前言第一篇 TCPIP协议详解第1章 TCPIP协议族 1.1 TCPIP协议族体系结构以及主要协议 1.1.1 数据链路层 1.1.2 网络层 1.1.3 传输层 1.1.4 应用层 1.2 封装 1.3 分用 1.4 测试网络 1.5 ARP协议工作原理 ...
什么是实用技巧,就是那种能经常用得着的值得收藏起来的应用方法。本文 中笔者就将向大家介绍35种Windows操作系统技巧,招招实用,招招值得你把 他保存到你的电脑中或者把这篇文章的地址收藏到收藏夹里。 1、...
本资源提供了一个全面且功能完善的ASP网上购物系统,不仅包含了详尽的源代码,还有一篇深入探讨该系统设计实现过程的论文。这个系统采用先进的ASP技术构建,旨在为用户提供一个便捷、安全且个性化的在线购物体验。 ...
这篇论文主要介绍了一种基于卷积神经网络(CNN)的焊接缺陷检测方法,称为轻量且更快速的YOLO(LF-YOLO)。论文指出X射线图像在制造业中具有重要的质量保证作用,因为它可以反映焊接区域的内部情况。然而,不同缺陷...
Android数据库最基础的一个例子(本人已测试,可以运行) 为launcher添加一个仿Mac的dock(附源码) 使用Gallery实现Tab 仿QQ--tab切换动画实例 Android 小项目之---猜扑克牌游戏 (附源码) fleep滑动切换tab(切换...
第二篇为进阶篇,主要介绍了Alamofire网络服务、数据的持久化、多线程、CoreText、CoreImage、Storyboard、自动化测试、性能分析、本地化、加密与安全等实用技术。第三篇为实例篇,通过对实体层、表现层和逻辑层三层...
从电脑使用和维护的角度讲述了 软件安装,GHOST等硬盘实用软件的使用,升级 BIOS和电脑超频,硬件性能测试,计算 机病毒防治,常见软件和硬件故障排除等内容 。通过本课程的学习,使学生获得计算机维 护与维修的...
一款非常适合学校建站的好程序,为学校单位量身订制,您不要懂网站开发语言,只要设置网站信息就可以做出自己的学校网站。 学校网站管理系统正式版前台功能介绍: 功能介绍: 1、系统管理: 网站属性、功能设置、...
延迟对象 延迟对象(Deferred Object,jQuery.Deferred对象)是一个可链接的(chainable)实用工具对象,实现了Promise接口,可以在回调队列中注册多个回调、调用回调队列并转发任何同步/异步函数的成败状态。...
高级篇(第13~19章),着重讲解了Cocos2D v2.0的高级知识、实用开发技巧和最佳实践,包括粒子系统、CocosBuilder和Shader、在游戏中添加对IAP的支持、性能分析与优化、产品的测试/发布/推广,以及Cocos2D的延伸技术...
.NET20 一种简单的窗口控件UI状态控制方法 翻译MSDN文章 —— 泛型FAQ:最佳实践 Visual C# 3.0 新特性概览 C# 2.0会给我们带来什么 泛型技巧系列:如何提供类型参数之间的转换 C#2.0 - Object Pool 简单实现 ...
文将对 Linux™ 程序员可以使用的内存管理技术进行概述,虽然关注的重点是 C 语言,但同样也适用于其他语言。文中将为您提供如何管理内存的细节,然后将进一步展示如何手工管理内存,如何使用引用计数或者内存池来半...
第一篇 使用PHP 第1章 PHP快速入门教程 1.1 开始之前:了解PHP 1.2 创建一个示例应用:Bob汽车零部件商店 1.2.1 创建订单表单 1.2.2 表单处理 1.3 在HTML中嵌入PHP 1.3.1 使用PHP标记 1.3.2 PHP语句 1.3.3 空格 ...
第一篇 使用PHP 第1章 PHP快速入门教程 1.1 开始之前:了解PHP 1.2 创建一个示例应用:Bob汽车零部件商店 1.2.1 创建订单表单 1.2.2 表单处理 1.3 在HTML中嵌入PHP 1.3.1 使用PHP标记 1.3.2 PHP语句 1.3.3 ...