>  기사  >  Java  >  Java 프로그래밍에서 "성능을 위해" 수행되어야 하는 몇 가지 작업

Java 프로그래밍에서 "성능을 위해" 수행되어야 하는 몇 가지 작업

伊谢尔伦
伊谢尔伦원래의
2016-11-29 10:46:26902검색

최근 머신 메모리가 또 꽉 찼습니다. 새로운 머신 메모리를 추가하는 것 외에도 코드를 너무 무심코 작성하는 경우가 많으므로 주의해야 합니다. 검토되고 억제되었습니다.

Java 프로그래밍에서 성능을 위해 수행되어야 하는 몇 가지 작업

다음은 Java 프로그래밍에서 최대한 수행해야 할 몇 가지 사항을 온라인 리소스를 참조하여 요약한 것입니다.

 1. 상황에 맞게 싱글턴을 사용해 보세요

싱글턴을 사용하면 부하를 줄이고, 로딩 시간을 단축하고, 로딩 효율을 높일 수 있지만, 모든 곳에서 싱글턴을 사용하기에 적합한 것은 아닙니다. 예를 들면, 싱글턴은 주로 다음 세 가지 측면에 적용 가능합니다.

첫째, 스레드 동기화를 통해 리소스 사용을 제어하고 리소스에 대한 동시 액세스를 제어합니다. 제어 리소스 절약 목적을 달성하기 위한 인스턴스 생성

셋째, 데이터 공유를 제어하여 직접적인 연결을 설정하지 않고 관련되지 않은 여러 프로세스 또는 스레드 간의 통신을 허용합니다.

 2. 정적 변수를 임의로 사용하지 마십시오

객체가 참조된 정적 변수로 정의되면 gc는 일반적으로 이 객체가 차지하는 메모리를 회수하지 않는다는 점을 알아야 합니다. as

이때 정적 변수 b의 수명주기는 클래스 A와 동기화됩니다. 클래스 A가 언로드되지 않으면 객체 b는 프로그램이 종료될 때까지 메모리에 상주합니다.
public class A{
static B b = new B();
}

 3. 너무 많은 자바 객체를 너무 자주 생성하지 않도록 하세요

자주 호출되는 메소드와 루프에서 새로운 객체를 생성하는 것을 피하세요. 이러한 객체를 가비지 수집 및 처리하고 제어 내에서 객체를 최대한 재사용하는 데 필요한 시간은 객체를 기본 데이터 유형 또는 배열로 바꾸는 것이 가장 좋습니다.

4. 최종 수식어를 사용해 보세요

최종 수식어가 있는 클래스는 파생될 수 없습니다. Java Core API에는 java.lang.String 등 final을 적용한 예가 많이 있습니다. String 클래스에 final을 지정하면 사용자가 length() 메서드를 재정의할 수 없습니다. 또한 클래스가 final이면 해당 클래스의 모든 메서드도 final입니다. Java 컴파일러는 모든 최종 메소드를 인라인할 수 있는 기회를 찾습니다(이는 특정 컴파일러 구현에 따라 다름). 이렇게 하면 성능이 평균 50% 향상될 수 있습니다.

5. 로컬 변수를 사용해 보세요

메소드 호출 시 전달된 매개변수와 호출 시 생성된 임시 변수는 스택(Stack)에 저장되므로 속도가 더 빠릅니다. 정적 변수, 인스턴스 변수 등과 같은 다른 변수는 힙에 생성되며 속도가 느립니다.

 6. 포장 유형과 기본 유형 모두의 사용 상황을 처리하도록 노력하세요

포장 유형과 기본 유형은 사용 중에 서로 변환될 수 있지만, 이들이 생성하는 메모리는 기본 유형 데이터는 스택에서 생성되고 처리됩니다. 래퍼 유형은 객체이고 인스턴스는 힙에서 생성됩니다.

컬렉션 클래스 개체에서는 포장 유형이 개체가 필요한 처리에 적합하며 기타 처리에는 기본 유형을 사용하는 것이 좋습니다.

 7. 동기화를 주의 깊게 사용하고 동기화 방법을 최소화하세요

동기화를 수행하려면 비용만큼 많은 시스템 오버헤드가 필요하고 교착 상태가 발생할 수도 있다는 사실은 모두가 알고 있으므로 불필요한 동기화는 피하세요. 제어. 동기화 메소드가 호출되면 현재 객체는 직접 잠기며, 해당 메소드가 실행될 때까지 다른 스레드는 현재 객체의 다른 메소드를 호출할 수 없습니다. 따라서 동기화 메소드는 가능한 한 작아야 하며, 코드 블록 동기화 대신 메소드 동기화를 최대한 사용해야 합니다.

8. 문자열 연결을 위해 StringBuilder 및 StringBuffer를 사용해 보세요.

이에 대해서는 자세히 설명하지 않겠습니다.

9. finalize 메소드를 사용하지 마세요

실제로 finalize 메소드에서 리소스 정리를 완료하는 것은 매우 나쁜 선택입니다. GC 작업량, 특히 재활용이 많기 때문입니다. 메모리가 생성되면 애플리케이션이 일시 중지되는 경우가 많으므로 리소스를 정리하기 위해 finalize 메서드를 사용하도록 선택하면 GC에 더 큰 부담이 발생하고 프로그램 작업 효율성이 저하됩니다.

10. 객체 대신 기본 데이터 유형을 사용해 보십시오.

String str = "hello";

위의 방법은 "hello" 문자열을 생성하고 JVM 문자 캐시 풀은 이 문자열도 캐시합니다.

String str = new String("hello")

이때 문자열을 생성하는 것 외에도 다음에서 참조하는 기본 String 객체가 있습니다. str에는 h, e, l, l, o

를 순서대로 저장하는 char[] 배열도 포함되어 있습니다. 11. 단일 스레드는 HashMap, ArrayList

HashTable, Vector를 사용해야 합니다. 등. 성능을 저하시키는 동기화 메커니즘이 사용됩니다.

12. 최대한 합리적으로 HashMap을 생성하세요

더 큰 hashMap을 생성하려면 다른 생성자를 최대한 활용하세요

public HashMap(intinitialCapacity, float loadFactor )

HashMap의 다중 해시 재구성을 피하십시오. 확장은 기본적으로 초기 용량이 16이고, loadFactor가 얼마나 필요한지 정확하게 아는 것이 좋습니다. 필요한 최적의 크기입니다. 해시테이블과 벡터의 경우에도 마찬가지입니다.

 13. 변수의 반복계산 최소화

  如

  for(int i=0;i

  应该改为

  for(int i=0,len=list.size();i

  并且在循环中应该避免使用复杂的表达式,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。 

  14. 尽量避免不必要的创建

  如

  A a = new A();

  if(i==1){list.add(a);}

  应该改为

  if(i==1){

  A a = new A();

  list.add(a);}

  15. 尽量在finally块中释放资源

  程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally块中去做。不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭。 

  16. 尽量使用移位来代替'a/b'的操作

  "/"是一个代价很高的操作,使用移位的操作将会更快和更有效

  如

  int num = a / 4;

  int num = a / 8;

  应该改为

  int num = a >> 2;

  int num = a >> 3;

  但注意的是使用移位应添加注释,因为移位操作不直观,比较难理解

  17.尽量使用移位来代替'a*b'的操作

  同样的,对于'*'操作,使用移位的操作将会更快和更有效

  如

  int num = a * 4;

  int num = a * 8;

  应该改为

  int num = a

  int num = a

  18. 尽量确定StringBuffer的容量

  StringBuffer 的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再 丢弃旧的数组。在大多数情况下,你可以在创建 StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。 

  如:StringBuffer buffer = new StringBuffer(1000);  

  19. 尽量早释放无用对象的引用

  大部分时,方法局部引用变量所引用的对象 会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null。

  例如:

Public void test(){
Object obj = new Object();
……
Obj=null;
}

上面这个就没必要了,随着方法test()的执行完成,程序中obj引用变量的作用域就结束了。但是如果是改成下面:

Public void test(){
Object obj = new Object();
……
Obj=null;
//执行耗时,耗内存操作;或调用耗时,耗内存的方法
……
}

这时候就有必要将obj赋值为null,可以尽早的释放对Object对象的引用。

  20. 尽量避免使用二维数组

  二维数据占用的内存空间比一维数组多得多,大概10倍以上。

  21. 尽量避免使用split

  除非是必须的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需 要频繁的调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。

  22. ArrayList & LinkedList

  一 个是线性表,一个是链表,一句话,随机查询尽量使用ArrayList,ArrayList优于LinkedList,LinkedList还要移动指 针,添加删除的操作LinkedList优于ArrayList,ArrayList还要移动数据,不过这是理论性分析,事实未必如此,重要的是理解好2 者得数据结构,对症下药。

  23. 尽量使用System.arraycopy ()代替通过来循环复制数组

  System.arraycopy() 要比通过循环来复制数组快的多 

  24. 尽量缓存经常使用的对象

  尽可能将经常使用的对象进行缓存,可以使用数组,或HashMap的容器来进行缓存,但这种方式可能导致系统占用过多的缓存,性能下降,推荐可以使用一些第三方的开源工具,如EhCache,Oscache进行缓存,他们基本都实现了FIFO/FLU等缓存算法。

  25. 尽量避免非常大的内存分配

  有时候问题不是由当时的堆状态造成的,而是因为分配失败造成的。分配的内存块都必须是连续的,而随着堆越来越满,找到较大的连续块越来越困难。

  26. 慎用异常

  当创建一个异常时,需要收集一个栈跟踪(stack track),这个栈跟踪用于描述异常是在何处创建的。构建这些栈跟踪时需要为运行时栈做一份快照,正是这一部分开销很大。当需要创建一个 Exception 时,JVM 不得不说:先别动,我想就您现在的样子存一份快照,所以暂时停止入栈和出栈操作。栈跟踪不只包含运行时栈中的一两个元素,而是包含这个栈中的每一个元素。

  如果您创建一个 Exception ,就得付出代价。好在捕获异常开销不大,因此可以使用 try-catch 将核心内容包起来。从技术上讲,您甚至可以随意地抛出异常,而不用花费很大的代价。招致性能损失的并不是 throw 操作——尽管在没有预先创建异常的情况下就抛出异常是有点不寻常。真正要花代价的是创建异常。幸运的是,好的编程习惯已教会我们,不应该不管三七二十一就 抛出异常。异常是为异常的情况而设计的,使用时也应该牢记这一原则。

相关回复:

  xuanyuan 写道

  7.慎用synchronized,尽量减小synchronize的方法

  re:同意,不过文中有个地方说错了,使用synchronized关键字并不一定都是锁定当前对象的,要看具体的锁是什么。如果是在方法上加的synchronized,则是以对象本身为锁的,如果是静态方法则锁的粒度是类。

  ---------------

  9.尽量不要使用finalize方法

  re:同意,其实不推荐用finalize方法的根本原因在于,JVM的规范并不保证何时执行该方法,所以用这个方法来释放资源很不合适,有可能造成长时间资源得不到释放。

  ---------------

  16.尽量使用移位来代替'a/b'的操作;17.尽量使用移位来代替'a*b'的操作

  re:个人不太同意这两条。这样做确实有更好的性能,但是却牺牲了可读性。这两个操作符对很多程序员来说并不直观。我认为在如今硬件价格不那么昂贵的情况下,略微牺牲一些性能,换来更好的可读性和可维护性是好的选择。

  wuzhengju 写道

19.尽量早释放无用对象的引用

  大部分时,方法局部引用变量所引用的对象 会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null。

  例如:

Public void test(){
Object obj = new Object();
……
Obj=null;
}

上面这个就没必要了,随着方法test()的执行完成,程序中obj引用变量的作用域就结束了。但是如果是改成下面:

Public void test(){
Object obj = new Object();
……
Obj=null;
//执行耗时,耗内存操作;或调用耗时,耗内存的方法
……
}

如果Object obj = new Object(); 如果这对象并不是大对象,这有必要吗?Obj=null;只是告诉jvm这个对象已经成为垃圾,至于什么时候回收,还不能确定! 这可读性也不好!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.