Java程序性能调优的基本知识和JDK调优

一 基本知识

1.1 性能是什么

在性能调优之前,我们首先来了解一下性能是什么?关于性能,我想每个学习过Java的人都能列出几点,甚至可以夸夸其谈。在《Java TM Platform Performance》一书中,定义了如下五个方面来作为评判性能的标准:

1) 运算的性能——哪一个算法的执行性能最好?

2) 内存的分配——程序运行时需要耗费多少内存?

3) 启动的时间——程序启动需要多长时间?这在Web项目中的影响不大,但要注意部分程序需要部署或运行在客户端时的情形(比如applet程序)。

4) 程序的可伸缩性——在压力负载的情况下,程序的性能如何?

5) 性能的感知——用户在什么情况下会觉得程序的性能不好?

以上五个方面,在具体的使用场景可以有选择的去评判。至于这五方面的性能调优,在后续的章节中将会陆续的给以相应的性能调优策略。

1.2 调优的规则

我们只需要关心对我们程序有影响,可以察觉到的性能问题,而不是每一个类中的每一个方法我们都需要想方设法的提高性能。如果程序的性能没有达到我们所期 望的要求,我们才需要考虑如何优化性能。同样的,晦涩的代码虽然提高了程序的性能,但同时可能带给我们的是维护的噩梦。我们需要折中的考虑以上两种情况, 使得程序的代码是优美的,并且运行的足够快,达到客户所期望的性能要求。

优化代码甚至会导致不良的结果,Donald Knuth(一位比较牛比较有影响的人物,具体是谁,我也忘了,谁知道,可以告诉我一下,谢谢!)曾说过,“Premature optimization is the root of all evil”。在开始性能调优前,需要先指出不优化代码的一些理由。

1) 如果优化的代码已经正常工作,优化后可能会引入新的bug;

2) 优化代码趋向于使代码更难理解和维护;

3) 在一个平台上优化的代码,在另一个平台上可能更糟;

4) 花费很多时间在代码的优化上,提高了很少的性能,却导致了晦涩的代码。 确实,在优化前,我们必须认真的考虑是否值得去优化。

1.3 调优的步骤

一般我们提高应用程序的性能划分为以下几个步骤:

1) 明确应用程序的性能指标,怎样才符合期望的性能需求;

2) 在目标平台进行测试;

3) 如果性能已经达到性能指标,Stop;

4) 查找性能瓶颈;

5) 修改性能瓶颈;

6) 返回到第2步。

二 JDK调优

2.1 选择合适的JDK版本

不同版本的JDK,甚至不同厂家的JDK可能都存在着很大的差异,对于性能优化的程度不同。一般来说,尽可能选择最新发布的稳定的JDK版本。最新的稳定的JDK版本相对以前的JDK版本都会做一些bug的修改和性能的优化工作。

2.2 垃圾收集Java堆的优化

垃圾收集就是自动释放不再被程序所使用的对象的过程。当一个对象不再被程序所引用时,它所引用的堆空间可以被回收,以便被后续的新对象所使用。垃圾收集 器必须能够断定哪些对象是不再被引用的,并且能够把它们所占据的堆空间释放出来。如果对象不再被使用,但还有被程序所引用,这时是不能被垃圾收集器所回收 的,此时就是所谓的“内存泄漏”。监控应用程序是否发生了内存泄漏,有一个非常优秀的监控工具推荐给大家——Quest公司的JProbe工具,使用它来 观察程序运行期的内存变化,并可产生内存快照,从而分析并定位内存泄漏的确切位置,可以精确定位到源码内。这个工具的使用我在后续的章节中还会做具体介 绍。

Java堆是指在程序运行时分配给对象生存的空间。通过-mx/-Xmx和-ms/-Xms来设置起始堆的大小和最大堆的大小。 根据自己JDK的版本和厂家决定使用-mx和-ms或-Xmx和-Xms。Java堆大小决定了垃圾回收的频度和速度,Java堆越大,垃圾回收的频度越 低,速度越慢。同理,Java堆越小,垃圾回收的频度越高,速度越快。要想设置比较理想的参数,还是需要了解一些基础知识的。 Java堆的最大值不能太大,这样会造成系统内存被频繁的交换和分页。所以最大内存必须低于物理内存减去其他应用程序和进程需要的内存。而且堆设置的太 大,造成垃圾回收的时间过长,这样将得不偿失,极大的影响程序的性能。以下是一些经常使用的参数设置:

1) 设置-Xms等于-XmX的值;

2) 估计内存中存活对象所占的空间的大小,设置-Xms等于此值,-Xmx四倍于此值;

3) 设置-Xms等于-Xmx的1/2大小;

4) 设置-Xms介于-Xmx的1/10到1/4之间;

5) 使用默认的设置。

大家需要根据自己的运行程序的具体使用场景,来确定最适合自己的参数设置。 除了-Xms和-Xmx两个最重要的参数外,还有很多可能会用到的参数,这些参数通常强烈的依赖于垃圾收集的算法,所以可能因为JDK的版本和厂家而有所 不同。但这些参数一般在Web开发中用的比较少,我就不做详细介绍了。在实际的应用中注意设置-Xms和-Xmx使其尽可能的优化应用程序就行了。对于性 能要求很高的程序,就需要自己再多研究研究Java虚拟机和垃圾收集算法的机制了。可以看看曹晓钢翻译的《深入Java虚拟机》一书。

 

第二篇:JAVA基础知识总结_陈建红

1. 运行时异常与一般异常有何区别?

异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。JAVA编译器要求方法必须声明抛出可能发生的非运行时异常,但并不要求必须声明抛出未捕获的运行时异常。

2. 说出ArrayList,Vector,LinkedList的存储性能和特性?

ArrayList 和Vector 都是使用数组方式存储数据,此数据元素数大于实际存储的数据以便增加和插入元素,他们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动到内存操作,所以索引数据快而插入数据慢,Vecor由于使用了synchronized方法,通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。

3. 谈谈final,finally,finalize的区别。

Final用于声明属性方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。 Finally是异常处理语句结构的一部分,表示总是执行的。

Finalize 是object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件。

4. &和&&的区别?

&是位运算符,表示按位与运算,&&是逻辑运算符,表示逻辑与。

5. HashMap和Hashtable的区别?

HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。

6. Collection和Collections的区别。

Collection是集合类的上级接口,继承与他的接口主要是Set和List.

Collections是针对集合类的一个帮助类,他提供一系列静态方法实现集合的搜索,排序,线程安全化等操作。

7. 什么是GC?为什么要有GC?

GC是垃圾收集的意思(Gabage Collection),内存处理时程序人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,JAVA提供的GC功能可以自动检测对象是否超过作用域从而达到自动回收内存的目的,java语言没用提供释放已分配内存的显示操作方法。

8. Overload(重载) 和 Override(重写)的区别。Overloaded的方法是否可以改变返回

值的类型?

方法的重写Overriding和重载Overloading是JAVA多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding),子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的

定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,他们或有不同的参数个数,或有不同的参数类型,则称为方法的重载(Overloading)。Overloading的方法是可以改变返回值的类型。

9. sleep()和wait()有什么区别/

sleep是线程类(Thread)的方法,导致此线程暂停执行指定的时间,给执行机会给其他线程,但是监控状态依然保持,到时后后自动恢复。调用sleep不会释放对象锁。

Wait 是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify(或notifyAll)后本线程才进入对象锁定池准备获取对象锁进入运行状态。

10. List,set,map的区别级各自的特点?

List和set都是继承自collection接口。

List以特定次序来持有元素,可以有重复元素。

Set无法拥有重复元素,内部排序。

Map保持key-value值,value可重复,key不可重复。

11. error和exception有什么区别?

Error表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。

Exception表示一种设计或实现问题。也就是说,他表示如果程序运行正常,从不会发生的情况。

12. abstract class 和interface 的区别?

声明方法的存在而不去实现他的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其类型是一个抽象类,并让他指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法,abstract类的子类为他们的父类中的所有抽象方法提供实现,否则他们也是抽象类。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。

接口(interface)是抽象类的变体。在接口中,所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的没有一个程序体。接口只可以定义static final 成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义所有这种接口的方法。然后,然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否继承了接口。

13. abstract 方法是否可以同时是static?是否可以同时是native?是否可以是synchronized?

14. int和Integer有什么区别?

JAVA提供两种不同的类型:引用类型和原始类型(或内置类型)。Int是java的原始数据类型,Integer是java为int提供的封装类。Java为每个原始类型提供了封装类。

引用类型和原始类型的行为完全不同,并且他们具有不同的语义。引用类型和原始类型具有不同的特征和用法,他们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据是所指定的缺省值。对象引用实例变量的缺省值为null,而原始类型实例的缺省值与他们的类型有关。

15. String和stringbuffer的区别?

Java平台提供了两个类,String和StringBuffer ,他们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个SringBuffer类提供的字符串进行修改。当你知道字符串数据要改变的时候你就会可以使用StringBuffer。典型地,你可以使用StringBuffer来动态构造字符数据。

16. 同步和异步有什么异同,在什么情况下使用他们?

如果数据将在线程间共享,例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。 当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效。

17. 堆和栈有什么区别?

栈是一种线形集合,其添加和删除元素的操作应在同一段完成。栈按照后进先出的方式进行处理。

堆是栈的一个组成元素

18. forward和redirect的区别

forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取出来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送来的内容是从哪儿来的,所以他的地址栏中还是原来的地址。

Redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求,所以session,request参数都可以获取。

19. Switch是否能作用在byte上,能否作用在long上,能否作用在string上?

Switch(expr1)中,expr1是一个整数表达式。因此传递给switch和case语句的参数应该是int,shor,char或者byte。Long,String都不能作用于switch.

20. 请说出你所知道的线程同步的方法?

wait():使一个线程处于等待状态,并且释放所持有的对象lock.

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕获interruptedException异常。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。 Allnotify():唤醒所偶处于等待状态的线程,注意并不能给所有唤醒线程一个对象锁,而是让他们竞争。

21. 描述下JVM加载class文件的原理机制。

JVM中类的装载是由ClassLoader和他的子类来实现的,JAVA ClassLoader是一个重要的JAVA运行时系统组件。他负责在运行时查找和装入类文件的类。

22. char型变量能不能存储一个中文汉字?为什么?

能够定义成为一个中文的,因为Java中是以Unicode编码,一个char占16个字节,所以放一个中文是没问题的。

23. 多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?

多线程有两种实现方法,分别是继承Thread类与实现Runnable接口。

同步的实现方法有2种,分别是synchronized,wait与notify

24. JAVA语言中如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么

意思?在try块中可以抛出异常吗?

Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java中每个一场都是一个对象,他是Throwable类或其它子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获这个异常并进行处理。Java的异常处理是通过5个关键字来实现的:try、catch、throw、throws、和finally。一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throws)一个异常,这时候你可以通过它的类型来捕获(catch)它,或最后(finally)由缺省处理器来处理。

用try来指定一块预防所有“异常”的程序。紧跟在try程序后面,应包含一个catch字句来指定你所要想捕获的异常类型。

Throw语句用来明确的抛出一个“异常”;

Throws用来证明一个成员函数可能抛出的各种异常;

Finally为确保一段代码不管发生什么异常都被执行一段代码。

可以在一个成员函数调用外面写一个try语句,在这个成员函数内写另一个try语句保护其他代码。每当遇到一个try语句,异常的框架就放到堆栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种异常进行处理,堆栈就会展开,直到遇到有处理这种异常的try语句。

25. JAVA中有几种类型的流?JDK为每种类型的流提供了一些抽象以供继承,并说出他们

分别是那些类?

字节流,字符流。字节流继承与InputStream\OutputStream,字符流继承于InputStreamReader\OutputStreamWriter.在Java.io包中还有许多其它的流,主要是为了提

高性能和使用方便。

26. JAVA中实现多态的机制是什么?

方法的重写Overriding和重载OverLoading是java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载是一个类中多态性的一种表现。

27. 什么事JAVA序列化,如何实现java序列化?

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。

序列化的实现:将需要被序列化的类实现Seriallizable接口,该接口没有需要实现的方法,implements serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则使用输入流。

28. String是最基本的数据类型吗?

最基本的数据类型包括:byte int short long boolean char double float

Java.lang.String类是final类型的,因此不可以继承这个类,不能修改这个类。为了提高效率节省空间,我们应该使用StringBuffer类

29. 面向对象的特征有哪些?

① 抽象

② 继承

③ 多态性

④ 封装

30. 正则表达式

这部分经常在笔试题中出现,具体内容还是每个人根据自己的情况去学习

31.Scoket通信

知识点提出来,各位自己研究

以上仅供参考,不完善的地方提出来,谢谢!

相关推荐