Java プログラミングで「パフォーマンスのために」行うべきこと

伊谢尔伦
リリース: 2016-11-29 10:46:26
オリジナル
915 人が閲覧しました

最近のマシンのメモリが再びいっぱいになっています。新しいマシンのメモリを追加するだけでなく、多くのコードがあまりにも無造作に書かれているため、これらの悪い習慣やプログラミング言語の理解の欠如も抑制する必要があります。

Java プログラミングで「パフォーマンスのために」行うべきこと

以下は、インターネットのリソースに基づいて Java プログラミングで可能な限り行うべきことのいくつかです。

1. 適切な状況でシングルトンを使用するようにしてください

シングルトンを使用すると、ロードの負担が軽減され、ロード時間が短縮され、ロード効率が向上しますが、すべての場所がシングルトンに適しているわけではありません。 簡単に言うと、シングルトンは主に次の 3 つに当てはまります。側面:

第一に、スレッド同期を通じてリソースの使用を制御し、リソースへの同時アクセスを制御します。

第二に、リソースを節約する目的を達成するためにインスタンスの生成を制御します。

第三に、データ共有を制御し、複数間の通信を可能にします。直接的な関係を確立せずに、無関係なプロセスまたはスレッドを作成します。

2. 静的変数の使用を任意で避けるようにしてください

オブジェクトが参照される静的変数として定義されている場合、gc は通常、

public class A{
static B b = new B();
}
ログイン後にコピー

など、このオブジェクトによって占有されているメモリを再利用しないことを知っておく必要があります。 、静的変数 b ライフサイクルはクラス A と同期されます。クラス A がアンロードされない場合、オブジェクト b はプログラムが終了するまでメモリ内に常駐します。

3. あまりにも多くの Java オブジェクトを作成しないようにしてください

システムはオブジェクトの作成に時間を費やすだけでなく、これらのオブジェクトのガベージ コレクションや処理にも時間を費やすため、頻繁に呼び出されるメソッドやループで新しいオブジェクトを作成しないようにしてください。オブジェクトを制御できる範囲で最大限に再利用するには、オブジェクトを基本的なデータ型または配列に置き換えるのが最善です。

4.final修飾子を使ってみる

final修飾子を持つクラスは派生できません。 Java コア API には、java.lang.String など、final を適用する例が多数あります。 String クラスに Final を指定すると、ユーザーは length() メソッドをオーバーライドできなくなります。さらに、クラスが Final の場合、そのクラスのすべてのメソッドが Final になります。 Java コンパイラは、すべての最終メソッドをインライン化する機会を探します (これは特定のコンパイラの実装によって異なります)。これにより、パフォーマンスが平均 50% 向上します。

5.ローカル変数を使ってみる

メソッド呼び出し時に渡されるパラメータや、呼び出し中に作成される一時変数はスタック(Stack)に保存されるので高速です。静的変数、インスタンス変数などの他の変数はヒープ内に作成されるため、速度が遅くなります。

6. パッケージ型と基本型の両方の使用状況に対応するようにしましょう

パッケージ型と基本型は使用時に相互に変換できますが、それらによって生成されるメモリ領域はまったく異なります 基本型 データの生成と処理。パッケージ化タイプはオブジェクトであり、インスタンスはヒープ内に生成されます。

コレクションクラスのオブジェクトでは、オブジェクトを必要とする処理にはパッケージ化型が適しており、それ以外の処理には基本型を使用することを推奨します。

7. synchronized は慎重に使用し、synchronize の方法は最小限に抑えてください

同期を実現するにはコストとして多くのシステムオーバーヘッドが必要で、デッドロックを引き起こす可能性があることは誰もが知っているので、不必要な同期制御は避けるようにしてください。 synchronize メソッドが呼び出されると、現在のオブジェクトは直接ロックされ、そのメソッドが実行されるまで他のスレッドは現在のオブジェクトの他のメソッドを呼び出すことができません。したがって、同期メソッドはできるだけ小さくする必要があり、可能な限りコード ブロック同期の代わりにメソッド同期を使用する必要があります。

8. 文字列接続に StringBuilder と StringBuffer を使ってみる

これについては詳しく説明しません。

9. Finalize メソッドを使用しないようにしてください

実際、Finalize メソッドでリソースのクリーンアップを完了するのは非常に悪い選択です。GC の負荷が高いため、特に若い世代のメモリをリサイクルする場合は、頻繁に問題が発生します。アプリケーションの問題が発生するため、リソースをクリーンアップするためにファイナライズ メソッドを使用すると、GC への負担が大きくなり、プログラムの実行効率が低下します。

10. オブジェクトの代わりに基本的なデータ型を使ってみてください

String str = "hello";

上記のメソッドは "hello" 文字列を作成し、JVM の文字キャッシュ プールもこの文字列をキャッシュします。

String str = new String("hello");

このとき、文字列の作成に加えて、str が参照する String オブジェクトの最下層には char[] 配列も含まれており、この char[] 配列には h、e が格納されます。 、l、o

11. 単一スレッドは HashMap、ArrayList

を使用するようにしてください。HashTable、Vector などは同期メカニズムを使用するため、パフォーマンスが低下します。

12. できるだけ合理的にHashMapを作成します

比較的大きなhashMapを作成したい場合は、別のコンストラクタを駆使してください

public HashMap(intInitialCapacity, floatloadFactor)

HashMapが複数回ハッシュ再構築されないようにします。拡張は非常にパフォーマンスを消費します。デフォルトでは、initialCapacity は 16 ですが、必要な容量はどれくらいですか? Hashtable と Vector についても同様です。 。 理由。

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 << 2;

  int num = a << 3;

  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这个对象已经成为垃圾,至于什么时候回收,还不能确定! 这可读性也不好!

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!