Java 性能优化系列之1[设计与程序优化]

性能

一般来说,性能通过以下几个方面来表现:

  • 执行速度
  • 内存分配
  • 启动时间
  • 负载承受能力

定量评测的性能指标:

  • 执行时间
  • CPU时间
  • 内存分配
  • 磁盘吞吐量
  • 网络吞吐量
  • 响应时间

调优的层面

  • 设计调优
  • 代码调优
  • JVM调优
  • 数据库调优
  • 操作系统调优

性能调优必须有明确的目标,不要为了调优而调优,如果当前程序并没有明显的性能问题,盲目地进行调整,其风险可能远远大于收益。

设计优化

1. 单例模式

对于系统的关键组件和被频繁使用的对象,使用单例模式可以有效地改善系统的性能

2. 代理模式

代理模式可以用来实现延迟加载,从而提升系统的性能和反应速度。

另外,可以考虑使用动态代理的方式 。 动态代理的方法有: JDK自带的动态代理, CGLIB, Javassist, 或ASM库。

3. 享元模式

好处:

1) 可以节省重复创建对象的开销

2) 对系统内存的需求减少

4. 装饰者模式

实现性能组件与功能组件的完美分离

5. 观察者模式

观察者模式可以用于事件监听、通知发布等场合。可以确保观察者在不使用轮询监控的情况下,及时收到相关的消息和事件。

6. Value Object 模式

将一个对象的各个属性进行封装,将封装后的对象在网络中传递,从而使系统拥有更好的交互模型,并且减少网络通信数据,从而提高系统性能。

7. 业务代理模式

将一组由远程方法调用构成的业务流程,封装在一个位于展示层的代理类中。

思考:

单例模式, 工厂模式和享元模式的差异?

常用优化组件和方法

1.缓冲

I/O 操作很容易成为性能瓶颈,所以,尽可能在 I/O 读写中加入缓冲组件,以提高系统的性能。

2. 缓存

缓存可以保存一些来之不易的数据或者计算结果,当需要再次使用这些数据时,可以从缓存中低成本地获取,而不需要再占用宝贵的系统资源。

Java缓存框架:

EHCache, OSCache,JBossCache

3. 对象复用 -- "池"

最熟悉的线程池和数据库连接池。

目前应用较为广泛的数据库连接池组件有C3P0 和Proxool.

4.并行替代串行

5. 负载均衡

跨JVM虚拟机,专门用于分布式缓存的框架--Terracotta, 使用Terracotta可以实现Tomcat的Session共享。

6. 时间换空间

7. 空间换时间

程序优化

1. 字符串优化处理

1)

		String str1 ="abc";
		String str2 ="abc";
		String str3 = new String("abc");

		System.out.println(str1==str2);  //true
		System.out.println(str1==str3);  //false
		System.out.println(str1==str3.intern()); //true

2) subString() 方法的内存泄漏

如果原字串很长,截取的字串却有比较短,使用以下方式返回:

new String(str1.substring(begin,end));

3) 字符串分割和查找

可以使用的方法:

split()方法   -- 最慢, 写法简单

StringTokenizer 方法  -- 较快,写法一般

indexOf()和subString() 方法 - 最快, 写法麻烦

package performance.program.string;

import java.util.StringTokenizer;

public class StringSplit {

	public static void splitMethod(String str) {

		long beginTime = System.currentTimeMillis();
		for (int i = 0; i < 10000; i++) {
			str.split(";");
		}

		long endTime = System.currentTimeMillis();
		System.out.println("splitMethod use " + (endTime - beginTime));
	}

	public static void tokenizerMethod(String str) {

		long beginTime = System.currentTimeMillis();

		StringTokenizer st = new StringTokenizer(str, ";");
		for (int i = 0; i < 10000; i++) {
			while (st.hasMoreTokens()) {
				st.nextToken();
			}
			st = new StringTokenizer(str, ";");
		}

		long endTime = System.currentTimeMillis();
		System.out.println("tokenizerMethod use " + (endTime - beginTime));
	}

	public static void IndexMethod(String str) {

		long beginTime = System.currentTimeMillis();
		String tmp = str;
		for (int i = 0; i < 10000; i++) {
			while (true) {
				String splitStr = null;
				int j = tmp.indexOf(";");
				if(j<0) break;
					splitStr = tmp.substring(0,j);
				tmp = tmp.substring(j+1);
			}
			tmp = str;
		}

		long endTime = System.currentTimeMillis();
		System.out.println("IndexMethod use " + (endTime - beginTime));
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String orgStr = null;
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < 1000; i++) {
			sb.append(i);
			sb.append(";");
		}
		orgStr = sb.toString();
		splitMethod(orgStr);
		tokenizerMethod(orgStr);
		IndexMethod(orgStr);

	}

}

4) 使用ChartAt 代替  startsWith 和 endsWith

性能要求比较高时,可以使用这条。

5) StringBuffer 和 StringBuilder

String result = "String" + "and" + "string"+"append";

这段看起来性能不高的代码在实际执行时反而会比StringBuilder 来的快。

原因是Java 编译器本身会做优化。

但是不能完全依靠编译器的优化, 还是建议显示地使用StringBuffer 或StringBuffer对象来提升系统性能。

StringBuffer 和 StringBuilder 的差异是:

StingBuffer 几乎所有的方法都做了同步

StringBuilder 并没有任何同步。

所以StringBuilder 的效率好于StringBuffer, 但是在多线程系统中,StringBuilder 无法保证线程安全。

另外,预先评估StringBuilder 的大小,能提升系统的性能。

2. 核心数据结构

1) List 接口

3种List实现: ArrayList,  Vector, 和LinkedList

ArrayList 和Vector 使用了数组实现, Vector 绝大部分方法都做了线程同步, ArrayList 没有对任何一个方法做线程同步。(ArrayList 和Vector 看上去性能相差无几)

使用LinkedList 对堆内存和GC的要求更高。

如果在系统应用中, List对象需要经常在任意位置插入元素,则可以考虑使用LinkedList 替代ArrayList

对于ArrayList从尾部删除元素时效率很高,从头部删除元素时相当费时,

而LinkedList 从头尾删除元素时效率相差无几,但是从中间删除元素时性能非常槽糕。

  头部 中间 尾部
ArrayList 6203 3125 16
LinkedList 15 8781 16

List 遍历操作

  ForEach 迭代器 for 循环
ArrayList 63 47 31
LinkedList 63 47 无穷大

2) Map 接口

实现类有: Hashtable, HashMap, LinkedHashMap和TreeMap

HashTable 和HashMap  的差异

HashTable大部分方法做了同步, HashTable 不允许key或者Value 使用null值;(性能上看起来无明显差异)

3) Set 接口

4) 优化集合访问代码

1. 分离循环中被重复调用的代码

for(int i=0;i<collection.size();i++)

替换成

int  count = collection.size();

for(int i=0;i<count;i++)

5). RandomAccess接口

3. 使用NIO 提升性能

在Java 的标准I/O中, 提供了基于流的I/O 实现, 即InputStream 和 OutputStream. 这种基于流的实现是以字节为单位处理数据, 并且非常容易建立各种过滤器。

NIO是 New I/O 的简称, 与旧式的基于流的 I/O 方法相对, 它表示新的一套Java I/O 标准。是在Java 1.4 中被纳入到JDK中的, 特性有

- 为所有的原始类型提供 Buffer 缓存支持

-  使用Java.nio.charset.Charset 作为字符集编码解码解决方案

- 增加通道对象(Channel), 作为新的原始I/O 抽象

- 支持锁和内存映射文件的文件访问接口

- 提供了基于Selector 的异步网络I/O

与流式的I/O 不同, NIO 是基于块(Block 的), 它以块为基本单位处理数据。

4. 引用类型。

强引用、软引用、弱引用和虚引用

强引用:

a)强引用可以直接访问目标对象

b) 强引用所指向的对象在任何时候都不会被系统回收

c)强引用可能导致内存泄漏

软引用:

软引用可以通过java.lang.ref.SoftReference来使用。 一个持有软引用的对象,不会被JVM很快回收, JVM会根据当前的使用状况来判断何时回收.当堆使用率临近阈值时,才会去回收软引用的对象。只要有足够的内存,软引用便可能在内存中存活相对长一段时间。因此,软引用可以用于实现对内存敏感的Cache.

弱引用:

在系统GC时,只要发现弱引用,不管系统堆空间是否足够,都会将对象进行回收。

虚引用

一个持有虚引用的对象,和没有引用几乎是一样的,随时都可能被垃圾回收器回收。但试图通过虚引用的get()方法去跌强引用时,总是会失败。并且,虚引用必须和引用队列一起使用,它的作用在于跟踪回收过程。

WeakHashMap类及其实现

WeakHashMap 是弱引用的一种典型应用,它可以作为简单的缓存表解决方案。

改善系统性能的技巧

1. 慎用异常

try catch 应用与循环体之外

2. 使用局部变量

调用方法时传递的参数以及在调用中创建的临时变量都保存在栈中,速度较快。

其他变量,如静态变量、实例变量等,都在堆中创建,速度较慢。

局部变量的访问速度远远高于类的成员变量。

3. 位运算代替乘除法

4. 替换Switch .

这一条应该注意的是一个新的思路问题, 使用不同的方式代替switch 语句。

这里的例子性能测试起来, switch 的性能反而更好一些。

package com.oscar999.performance.skill;

public class SwitchReplaceSkill {

	/**
	 * @param args
	 */

	protected void oldMethod() {
		int re = 0;
		for (int i = 0; i < 100000000; i++) {
			re = switchInt(i);
		}
	}

	public void newMethod() {
		int re=0;
		int[] sw= new int[]{0,3,6,7,8,10,16,18,44};
		for(int i = 0; i < 100000000; i++) {
			re = arrayInt(sw,i);
		}
	}

	protected int switchInt(int z) {
		int i = z % 10 + 1;
		switch (i) {
		case 1:
			return 3;
		case 2:
			return 6;
		case 3:
			return 7;
		case 4:
			return 8;
		case 5:
			return 10;
		case 6:
			return 16;
		case 7:
			return 18;
		case 8:
			return 44;
		default:
			return -1;
		}
	}
	protected int arrayInt(int[] sw,int z)
	{
		int i=z%10+1;
		if(i>8||i<1)
		{
			return -1;
		}else{
			return sw[i];
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SwitchReplaceSkill skill = new SwitchReplaceSkill();
		long begTime = System.currentTimeMillis();
		skill.oldMethod();
		long endTime = System.currentTimeMillis();
		System.out.println("Old Method use: "+(endTime-begTime));

		begTime = System.currentTimeMillis();
		skill.newMethod();
		endTime = System.currentTimeMillis();
		System.out.println("New Method use: "+(endTime-begTime));

	}

}

5. 一维数组代替二维数组

直接看例子:

package com.oscar999.performance.skill;

public class OneDime2TwoDime {

	protected void oldMethod(){
		int[][] array = new int[1000][1000];
		int re = 0;
		for(int k=0;k<100;k++)
		    for(int i=0;i<array[0].length;i++)
			    for(int j=0;j<array[0].length;j++)
				    array[i][j] = i;

		for(int k=0;k<100;k++)
		    for(int i=0;i<array[0].length;i++)
			    for(int j=0;j<array[0].length;j++)
				    re=array[i][j];		

	}

	protected void newMethod(){
		int[] array = new int[1000000];
		int re = 0;
		for(int k=0;k<100;k++)
			for(int i=0;i<array.length;i++)
				array[i] = i;
		for(int k=0;k<100;k++)
			for(int i=0;i<array.length;i++)
				re = array[i];
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		OneDime2TwoDime skill = new OneDime2TwoDime();
		long begTime = System.currentTimeMillis();
		skill.oldMethod();
		long endTime = System.currentTimeMillis();
		System.out.println("Old Method use: "+(endTime-begTime));

		begTime = System.currentTimeMillis();
		skill.newMethod();
		endTime = System.currentTimeMillis();
		System.out.println("New Method use: "+(endTime-begTime));
	}

}

Old Method use: 453
New Method use: 281

一维数字用的时间少了很多。

6. 提取表达式

有些重复运算的部分可以提取出来。

package com.oscar999.performance.skill;

public class ExtraExpression {

	protected void oldMethod(){
		double d = Math.random();
		double a = Math.random();
		double b = Math.random();
		double e = Math.random();
		double x,y;
		for(int i=0;i<10000000;i++)
		{
			x = d*a*b/3*4*a;
			x = e*a*b/3*4*a;
		}
	}

	protected void newMethod(){
		double d = Math.random();
		double a = Math.random();
		double b = Math.random();
		double e = Math.random();
		double x,y,t;
		for(int i=0;i<10000000;i++)
		{
			t = a*b/3*4*a;
			x = d*t;
			x = e*t;
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		OneDime2TwoDime skill = new OneDime2TwoDime();
		long begTime = System.currentTimeMillis();
		skill.oldMethod();
		long endTime = System.currentTimeMillis();
		System.out.println("Old Method use: "+(endTime-begTime));

		begTime = System.currentTimeMillis();
		skill.newMethod();
		endTime = System.currentTimeMillis();
		System.out.println("New Method use: "+(endTime-begTime));
	}

}

Old Method use: 109
New Method use: 79

7.  展开循环

展开循环是一种在极端情况下使用的优化手段,因为展开循可能会影响代码的可读性和可维护性, 所以取舍之间, 就要根据实际状况来看了。

看例子:

package com.oscar999.performance.skill;

public class ExpandCycle {
	protected void oldMethod(){
		int[] array = new int[9999999];
		for(int i=0;i<9999999;i++){
			array[i]=i;
		}
	}

	protected void newMethod(){
		int[] array = new int[9999999];
		for(int i=0;i<9999999;i+=3){
			array[i]=i;
			array[i+1]=i+1;
			array[i+2]=i+2;
		}
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ExpandCycle skill = new ExpandCycle();
		long begTime = System.currentTimeMillis();
		skill.oldMethod();
		long endTime = System.currentTimeMillis();
		System.out.println("Old Method use: "+(endTime-begTime));

		begTime = System.currentTimeMillis();
		skill.newMethod();
		endTime = System.currentTimeMillis();
		System.out.println("New Method use: "+(endTime-begTime));
	}

}

Old Method use: 78
New Method use: 47

8. 布尔运算代替位运算

虽然位运算的速度远远高于算术运算,但是在条件判断时,使用位运算替代布尔运算却是非常错误的选择。

对于"a&&b&&c", 只要有一项返回 false, 整个表达式就返回 false.

package com.oscar999.performance.skill;

public class BooleanBit {
	protected void oldMethod(){
		boolean a = false;
		boolean b = true;
		int d = 0;
		for(int i=0;i<10000000;i++)
			if(a&b&"Java_Perform".contains("Java"))
				d = 0;
	}

	protected void newMethod(){
		boolean a = false;
		boolean b = true;
		int d = 0;
		for(int i=0;i<10000000;i++)
			if(a&&b&&"Java_Perform".contains("Java"))
				d = 0;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		BooleanBit skill = new BooleanBit();
		long begTime = System.currentTimeMillis();
		skill.oldMethod();
		long endTime = System.currentTimeMillis();
		System.out.println("Old Method use: "+(endTime-begTime));

		begTime = System.currentTimeMillis();
		skill.newMethod();
		endTime = System.currentTimeMillis();
		System.out.println("New Method use: "+(endTime-begTime));
	}

}

Old Method use: 265
New Method use: 32

9. 使用 arrayCopy()

Java API 提高了数组复制的高效方法: arrayCopy().

这个函数是 native 函数, 通常native 函数的性能要优于普通的函数, 仅出于性能考虑, 在软件开发时, 应尽可能调用native 函数。

package com.oscar999.performance.skill;

public class ArrayCopy {
	protected void oldMethod(){
		int size = 100000;
		int[] array = new int[size];
		int[] arraydst = new int[size];
		for(int i=0;i<array.length;i++)
		{
			array[i]=i;
		}
		for(int k=0;k<1000;k++)
			for(int i=0;i<size;i++)
				arraydst[i]=array[i];
	}

	protected void newMethod(){
		int size = 100000;
		int[] array = new int[size];
		int[] arraydst = new int[size];
		for(int i=0;i<array.length;i++)
		{
			array[i]=i;
		}
		for(int k=0;k<1000;k++)
			System.arraycopy(array, 0, arraydst, 0, size);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ArrayCopy skill = new ArrayCopy();
		long begTime = System.currentTimeMillis();
		skill.oldMethod();
		long endTime = System.currentTimeMillis();
		System.out.println("Old Method use: "+(endTime-begTime));

		begTime = System.currentTimeMillis();
		skill.newMethod();
		endTime = System.currentTimeMillis();
		System.out.println("New Method use: "+(endTime-begTime));
	}

}

Old Method use: 156
New Method use: 63

10. 使用 Buffer 进行 I/O 操作

除NIO 外, 使用Java 进行I/O 操作有两种基本方式

1. 使用基于InputStream 和 OutoutStream的方式

2. 使用Writer 和Reader

无论使用哪种方式进行文件I/O , 如果能合理地使用缓冲, 就能有效提高I/O 的性能

package com.oscar999.performance.skill;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;

public class BufferStream {

	protected void oldMethod() {
		int count = 10000;
		try {
			DataOutputStream dos = new DataOutputStream(new FileOutputStream(
					"testfile.txt"));
			for (int i = 0; i < count; i++)
				dos.writeBytes(String.valueOf(i) + "\r\n");
			dos.close();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	protected void newMethod(){
		int count = 10000;
		try{
			DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("testfile.txt")));
			for (int i = 0; i < count; i++)
				dos.writeBytes(String.valueOf(i) + "\r\n");
			dos.close();
		}catch(Exception e)
		{
			e.printStackTrace();
		}

	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		BufferStream skill = new BufferStream();
		long begTime = System.currentTimeMillis();
		skill.oldMethod();
		long endTime = System.currentTimeMillis();
		System.out.println("Old Method use: " + (endTime - begTime));

		begTime = System.currentTimeMillis();
		skill.newMethod();
		endTime = System.currentTimeMillis();
		System.out.println("New Method use: " + (endTime - begTime));
	}

}

Old Method use: 516
New Method use: 0

11. 使用clone() 代替new

对于重量级对象, 优于对象在构造函数中可能会进行一些复杂且耗时额操作, 因此, 构造函数的执行时间可能会比较长。Object.clone() 方法可以绕过对象构造函数, 快速复制一个对象实例。由于不需要调用对象构造函数, 因此, clone 方法不会受到构造函数性能的影响, 快速生成一个实例。

12. 静态方法替代实例方法

使用static 关键字描述的方法为静态方法, 在Java 中, 优于实例方法需要维护一张类似虚函数表的结构,以实现对多态的支持。 与静态方法相比, 实例方法的调用需要更多的资源。 因此,对于一些常用的工具类方法,没有对其进行重载的必要,那么将它们声明为static, 便可以加速方法的调用。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-12 19:56:28

Java 性能优化系列之1[设计与程序优化]的相关文章

MySQL5.7性能优化系列(二)——SQL语句优化(3)——使用物化策略优化子查询

优化器使用物化策略(Materialization)来实现更有效的子查询处理.通过生成子查询结果作为临时表,通常在内存中,实现加速查询执行. MySQL首次需要子查询结果,将该结果实现为临时表.任何随后的结果都需要,MySQL再次指向临时表.优化器可以使用散列索引对表进行索引,以使查找更加快速和便宜.该索引是唯一的,它消除了重复,并使表格更小. 子查询实现可能时使用内存中临时表,如果表变得太大,则返回到磁盘存储. 如果不使用物化策略,则优化器有时将非相关子查询重写为相关子查询.例如,以下IN子查

性能优化系列八:MYSQL的配置优化

一.关键配置 1. 配置文件的位置 MySQL配置文件 /etc/my.cnf 或者 /etc/my.cnf.d/server.cnf 几个关键的文件:.pid文件,记录了进程id.sock文件,是内部通信使用的socket接口,比3306快.log文件,日志文件.cnf或.conf文件,配置文件安装目录:basedir数据目录:datadir 2. 在哪里保存你的数据 基本配置,指定数据目录,my.cnf或者server.cnf [mysqld]user = mysqlport = 3306s

最大化 AIX 上的 Java 性能,第 5 部分: 参考资料和结论

http://www.ibm.com/developerworks/cn/aix/library/es-Javaperf/es-Javaperf5.html 最大化 AIX 上的 Java 性能,第 5 部分: 参考资料和结论 这是由五个部分组成的系列的结束部分,此系列提供了相关技巧和技术,这些技巧和技术通常用于优化 Java™ 应用程序,以便在 AIX® 上实现最佳的性能.我们将讨论 AIX 上的 Java 性能优化的其他有趣方面,并查看几个案例研究,然后通过有用的参考资料列表结束此系列. 查

Java性能调优_深入Java程序性能调优(并行开发、JVM调优)

深入Java程序性能调优(阿姆达尔定律.缓存组件.并行开发.线程池.JVM调优)课程讲师:special课程分类:Java核心适合人群:初级课时数量:33课时更新程度:完成用到技术:阿姆达尔定律.缓存组件.并行开发.线程池.JVM调优涉及项目:模式在实际开发中运用深入Java程序性能调优下载: http://pan.baidu.com/s/1ntn0ZTB 密码: ijluJava性能调优:国内关于Java性能调优的课程非常少,如此全面深入介绍Java性能调优,北风算是独家,Special讲师,

推荐:Java性能优化系列集锦

Java性能问题一直困扰着广大程序员,由于平台复杂性,要定位问题,找出其根源确实很难.随着10多年Java平台的改进以及新出现的多核多处理器,Java软件的性能和扩展性已经今非昔比了.现代JVM持续演进,内建了更为成熟的优化技术.运行时技术和垃圾收集器.与此同时,底层的硬件平台和操作系统也在演化. 目录: 一.Java性能优化系列之一--设计优化 二.Java性能优化系列之二--程序优化 三.Java性能优化系列之三--并发程序设计详解 四.Java性能优化系列之四--Java内存管理与垃圾回收

Java GC 专家系列5:Java应用性能优化的原则

本文是GC专家系列中的第五篇.在第一篇理解Java垃圾回收中我们学习了几种不同的GC算法的处理过程,GC的工作方式,新生代与老年代的区别.所以,你应该已经了解了JDK 7中的5种GC类型,以及每种GC对性能的影响. 在第二篇Java垃圾回收的监控中介绍了在真实场景中JVM是如何运行GC,如何监控GC数据以及有哪些工具可用来方便进行GC监控. 在第三篇GC 调优中基于真实案例介绍了可用于GC调优的最佳选项.同时也描述了如何通过降低移动到老年代中对象的数量来缩短Full GC耗时,以及如何设置GC类

《Java程序性能优化》学习笔记 Ⅰ设计优化

豆瓣读书:http://book.douban.com/subject/19969386/ 第一章 Java性能调优概述 1.性能的参考指标 执行时间: CPU时间: 内存分配: 磁盘吞吐量: 网络吞吐量: 响应时间: 2.木桶定律   系统的最终性能取决于系统中性能表现最差的组件,例如window系统内置的评分就是选取最低分.可能成为系统瓶颈的计算资源如,磁盘I/O,异常,数据库,锁竞争,内存等. 性能优化的几个方面,如设计优化,Java程序优化,并行程序开发及优化,JVM调优,Java性能调

Java性能优化指南系列(一):概述和性能测试方法

Java性能分析是一门艺术和科学:科学指的是性能分析一般都包括大量的数字.测量和分析.绝大多数的性能工程师都有科学背景,运用科学的严谨是获取最大性能的重要组成部分.艺术部分指的是什么呢?性能调优是部分科学部分艺术的观点是很早就有的,但是关于性能的主题很少会给定特定的知识,这就是艺术的部分了,它和我们平常接受到的培训是不一样的,培训是确定了的.还有部分原因是对于某些人来说,性能调优是建立在深入的知识和经验上面的.这里艺术就是知识.经验和直觉的使用. 这本书不能帮助我们提升经验和直觉,但是可以帮助我

Java性能优化指南系列(二):Java 性能分析工具

进行JAVA程序性能分析的时候,我们一般都会使用各种不同的工具.它们大部分都是可视化的,使得我们可以直观地看到应用程序的内部和运行环境到底执行了什么操作,所以性能分析(性能调优)是依赖于工具的.在第2章,我强调了基于数据驱动的性能测试是非常重要的,我们必须测试应用的性能并理解每个指标的含义.性能分析和数据驱动非常类似,为了提升应用程序的性能,我们必须获取应用运行的相关数据.如何获取这些数据并理解它们是本章的主题.[本章重点介绍JDK中提供的性能分析工具] 操作系统工具及其分析 程序分析的起点并不