ホームページ  >  記事  >  Java  >  JVM メモリ管理-----その他の話 (以下、obj=null についても説明します)

JVM メモリ管理-----その他の話 (以下、obj=null についても説明します)

黄舟
黄舟オリジナル
2016-12-28 15:29:041278ブラウズ

プログラマーとしての訓練のプロセスは、さまざまな武術を練習する必要があるだけでなく、内なるエネルギーを養うことも同様に重要です。武術は主人公の力をすぐに高めることができますが、内なるエネルギーが低すぎると武術の10分の1も発揮できません。
そのため、LZ はデザインパターンなどの外部スキルを導入した後、直接内部の気の育成に切り替え、猿の友人全員で JVM の内容について議論しました。
本来、この章では GC に関連する内容を紹介するはずですが、その前に、LZ がちょっとしたプログラミングのコツについて説明します。もちろん、この小さなトリックは実際には GC と密接に関係しています。
猿の友人が Java メモリ関連の記事を読んだことがあるかどうかはわかりませんが、提案を列挙するときに、そのような提案を書くことがよくあります。
第 XX 条: オブジェクトを使用した後は、明示的にオブジェクトを null に設定してください。
元の言葉はこうではないかもしれませんが、意味は同じです。この言葉に書かれている意味は、今後コードを書くときはこう書けばいいということです。

Object obj = new Object();  
//to do something   
obj = null;

このコードには C/C++ スタイルが少しあります。obj=null は、C/C++ の delete obj または free(obj) を置き換えます。これは、GC がある場合でも、あるかのように動作する必要があることを思い出させるのと同じです。 GC がない場合は、使用後にオブジェクトに null 値を割り当てる必要があります。
まず第一に、LZ がここで説明したいのは、obj を null 値に代入することは、実際には C/C++ の delete とは大きく異なるということです。LZ が delete と free を置き換えると言う理由は、それらがコード内に出現するからです。場所も似ています。
obj=null は、new Object() によって作成されたインスタンスから参照変数 obj を切断することだけを行います。実際には、インスタンスによって占有されているメモリ空間はまだ解放されていません。
この提案を行うとき、多くのブロガーや本の著者の当初の意図は (おそらく多くのブロガーが本で読んだため)、できるだけ早く参照とインスタンスの間の関連付けを削除し、それによって GC にガベージ コレクションを実行させ、 を解放することでした。インスタンスが占有しているメモリ。場合によっては、これはメモリ リークを排除するためにも行われます。
LZ は個人的に、多くのブロガーや本の著者がこの提案をする本来の意図は、主に GC 原理やメモリ管理に慣れていないプログラマー向けであると感じています。なぜなら、関連する知識を理解していなければ、範囲を把握できなくなる可能性があるからです。変数を大量に使用すると、不必要なメモリの浪費につながる可能性があります (個人的にはこれが主な目的ではないと感じています。メモリ リークが発生しない限り、メモリは最終的に GC によって解放されるからです)、さらにはメモリ リークさえ発生します。
それで、安全のために、一部の専門家はそのような提案をしました。
これを考慮して、LZ は個人的に、全員が関連する知識を習得した後は、この提案を完全に無視してもよいと感じています。そうすると明らかにコードの明瞭性が低下し、コーディングの負担が増加します。ただし、その代わりに次のような利点があります。メモリリークがまったくない可能性もあります。
ここでは、オブジェクトに null 値を代入しないとメモリ リークが発生する場合がある理由について説明します。次のコード部分を考えてみましょう。

import java.util.Arrays;  
public class Stack {  
      
    private static final int INIT_SIZE = 10;  
    private Object[] datas;  
      
    private int size;  
    public Stack() {  
        super();  
        datas = new Object[INIT_SIZE];  
    }  
      
    public void push(Object data){  
        if (size == datas.length) {  
            extend();  
        }  
        datas[size++] = data;  
    }  
      
    public Object pop(){  
        if (size == 0) {  
            throw new IndexOutOfBoundsException("size is zero");  
        }  
        return datas[--size];  
    }  
      
    private void extend(){  
        datas = Arrays.copyOf(datas, 2 * size + 1);  
    }  
      
}

このコードは、スケーラブルな長さの単純なスタック実装です。テスト コードを作成してテストすると、問題がないことがわかります。ただし、申し訳ありませんが、ここでは明らかな「メモリ リーク」が発生しています。これは、一部のオブジェクトまたは参照が null 値に設定されていないことが原因です。
まだ見ていない場合は、LZ が少し思い出させてくれるので、すぐに気づくでしょう。このコードでは、配列内のオブジェクトは無限に増加するだけであり、スタック内の要素がポップされても減少することはなく、外部に表示されるスタックのサイズのみです。極端なシナリオを考えてみましょう。スタックに 100 万個のオブジェクトを入れ、最終的に 999,999 個が使用されているとします。スタックには使用可能なオブジェクトが 1 つだけ残っていますが、スタックにはまだ 100 万個のオブジェクトへの参照が保持されています。もし JVM が生き残ることができれば、間違いなくあなたは死ぬほど破壊されるでしょう。
私たちに欠けているのは、オブジェクトに null 値を割り当てるステップです。そのため、pop メソッドを次のメソッドに変更する必要があります。ArrayList の Remove メソッドのソース コードを見てください。これも同様の考え方です。 。

public Object pop(){  
        if (size == 0) {  
            throw new IndexOutOfBoundsException("size is zero");  
        }  
        Object data = datas[--size];  
        datas[size] = null;  
        return data;  
    }

这个内存泄露是非常隐蔽的,而且实际使用当中不一定就能发现,因为随着Stack对象的回收,整个数组也会被回收,到时内存泄露就被掩盖了。
所以个人觉得上述的那个建议是完全没有必要的,就算遵从了上面的建议,如果对内存管理不熟悉的话,也不会想到上面这个代码中的问题。如果想彻底的避免内存泄露的发生,机械式的主动将对象赋为空值,并不是一个可以从根本上解决问题的办法。
真正能够解决问题的办法,就是掌握好GC的策略与原理,定义一个变量时多注意变量的作用域,如此才可以更好的避免内存泄露。
所以学好GC原理还是很有必要的,希望准备走JAVA之路的朋友,尤其是从培训机构出来的猿友们(此处没有鄙视培训机构出来的猿友们的意思,因为LZ本人也是半路出家,从培训机构走上编程之路的程序猿之一),一定不要只专注于各个框架的使用以及业务的深入,虽然这些事很有必要,但并不是全部。
follow me and go the memory world 吧(语法都是浮云)。

 以上就是JVM内存管理------杂谈(借此也论一论obj=null)的内容,更多相关内容请关注PHP中文网(www.php.cn)!


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。