"test"
はString
リテラルであり、格納方法に関係なく (これは Java 開発中に変更されました)、ここで重要な点は、それが単一のオブジェクトであるということです。
Java 言語仕様を思い出してください。
…文字列リテラルは常に class の同じインスタンスを参照しますString
。これは、文字列リテラル (より一般的には、定数式の値である文字列 (§15.28)) が、メソッド String.intern を使用して一意のインスタンスを共有するために「インターン」されているためです。
したがって、常に同じインスタンスを参照するため、String
ループ内に新しい s が作成されることはありません。の内部容量が使い果たされた場合にのみ、ヒープの変更が発生します。"test"
String
ArrayList
の内部配列に最終的に必要なメモリArrayList
は、オブジェクト参照のサイズによって異なります。通常は、5000000*4 bytes
圧縮 oops を使用する 32 ビット JVM および 64 ビット JVM5000000*8 bytes
用であり、圧縮 oops を使用しない 64 ビット JVM 用です。
ここでの興味深い点は、www.kdgregory.comで説明されています。
オブジェクトが十分に大きい場合は、tenured 世代で直接作成されます。ユーザー定義のオブジェクトは、この動作をトリガーするのに必要な数のメンバーを持っていません (すべきではありません!) が、配列は次のようになります。
これは、oracle.com にある次の言葉と一致します。
Survivor 領域が小さすぎる場合、コレクションのコピーは Tenured 世代に直接オーバーフローします。
これは、サバイバー スペースに大きな配列が表示されない別の理由です。したがって、それらが Eden 空間から Tenured Generation にコピーされたために表示されないか、そもそも Tenured Generation で作成されたために表示されないかは、正確な構成によって異なります。しかし、サバイバースペースに現れないという結果は同じです。
そのため、デフォルト容量の でArrayList
が作成されると、内部配列はこのしきい値よりも小さくなり、容量を拡大するたびに次の配列も作成されます。ただし、新しい配列がこのしきい値を超えると、古い配列はすべてガベージになり、「生存者」として表示されなくなります。10
したがって、最初のループの終わりには、サイズがしきい値をはるかに超えているため、Survivor スペースをバイパスした配列が 1 つだけ残っています。2 番目のループは、メモリ管理に何も追加しません。一時的な を作成しますIterator
が、これらは決して「生き残る」ことはありません。