ねっとぱんだ-プログラミング勉強ブログ-

Webデザイン、プログラミングの勉強ブログ。

【java】javaのヒープ、メモリ管理の仕組み

メモリ領域について

参考
http://qiita.com/To_BB/items/e5540b80f08fd13c51b2

プログラム領域 プログラムの格納
静的領域 グローバル変数等の格納
ヒープ領域 動的に管理される領域の格納
スタック領域 CPUのレジスタを一時的に退避していたり、返り値を格納したり

詳しくは後日…

ヒープ

参考
http://promamo.com/?p=2828
https://ja.wikipedia.org/wiki/%E3%83%92%E3%83%BC%E3%83%97%E9%A0%98%E5%9F%9F
ヒープ領域 heap memory
OSやアプリケーションソフトが使用するメモリ領域の一種。用途に関係なく自由に確保できる。
OSからヒープメモリの確保した位置領域のアドレスが渡される→アプリケーションが使う
ガベージコレクション機能がないプログラミング言語ではヒープを手作業で解放するので誤解放や解放漏れなどが起こり易い。ヒープの解放漏れを「メモリリーク」という。

heap = 『山積み』という言葉の中の『山』をさす英単語

  • 2種類のラベルを持つ双方向リストによって構成
    連結リストhttps://ja.wikipedia.org/wiki/%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88
  • リストはひとつの「未使用」ノードが全体を占めている
  • メモリ確保関数によって、「未使用」ノードから必要な分を切り取って「使用中」ノードと「未使用」ノードに分ける
  • メモリ解放関数によってノードのラベルを「未使用」に書き換える
  • 解放のつど、あるいはカウンタによって一定水準に達した時、連続した個々の「未使用」ノードを結合し、大きな「未使用」ノードに還元
  • ノードが不足した場合には、OSに領域拡大を要求しヒープ領域を拡大するか、飛び飛びの未使用領域を連続な未使用領域に統合 = garbage collection
ガベージ・コレクション garbage collection
略→GC どこからも参照されない領域(オブジェクト?)を自動で削除する
ヒープメモリの利点
変数を動的に確保できる
ヒープメモリの欠点
領域の確認・確保の時間にばらつきがあり処理時間の見積もりが困難
領域の確保と解放の繰り返しによりヒープ上にどこからも参照しない領域が発生することがある
この領域を塵(garbage)といい、ヒープの未使用領域がgarbageによりバラバラに分断された状態をフラグメンテーション状態と呼ぶ

データ構造の一つのヒープもある

  • 「子要素は親要素より常に大きいか等しい(または常に小さいか等しい)」という制約を持つ木構造

https://ja.wikipedia.org/wiki/%E3%83%92%E3%83%BC%E3%83%97

JVMで使用するメモリ空間の構成

javaではメモリ管理がJVMによって自動的に行われている

図↓
http://promamo.com/?p=2828

http://ufcpp.net/study/computer/MemoryManagement.html

Eden領域
new演算子によって作成されたJavaオブジェクトが最初に格納される
Survivor領域
New領域のうち、ガベージ・コレクション実行時に破棄されなかったJavaオブジェクトが格納される
サイズが同じのFrom空間とTo空間によって構成されている
Tenured領域
長期間必要であると判断されたオブジェクトが格納される
Survivor領域で指定回数を超えてガベージ・コレクションで破棄されなかったオブジェクトがこの領域に移動
Permanent領域
ロードされたclassなどの情報が格納
Cヒープ領域
JVM自身が使用する
スタック領域
Javaスレッドのスタック領域

JVMではヒープ・メモリの構造は2つの領域に分けられる

New領域
Eden、From、To、Surviver
Old領域
Tenured

すぐ不要になるオブジェクトはNew領域のみで消える。長時間存在するオブジェクトはOldにとどまる。

JVMでは2種類のGCが実行される

Scavenge GC
New領域のみを対象とし短時間で終了。頻繁に実行する。
scavenge = ごみ箱の中から集める、清掃する
Full GC
New領域とOld領域両方を対象にしたGC。低頻度で実行。

二つのGCにより、オブジェクトは世代別に分割されることになる。

JVMののデフォルトでは、それぞれのサイズが
New領域が起動時2MB、最大16MB
Old領域が起動時4MB、最大48MB

ヒープ・メモリのサイズは変更できる

下記のコマンドで非標準オプションの一覧が表示できる

java -X

ヒープに関するオプション

ヒープに関するオプション
-XmsJavaの初期ヒープ・サイズを設定する
-XmxJavaの最大ヒープ・サイズを設定する
-XmnNEW領域のサイズ
-XX:SurvivorRatio=Eden領域のサイズをFromまたはTo領域のサイズで割った値(FromとTo領域は同じサイズ)

eclipseの場合
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1238805987
http://t12488mac.blogspot.jp/2011/07/eclipsejavavm.html
eclipse自身のヒープサイズ、プロジェクトに対する設定などがある。

JVMのガベージ・コレクションの動き

Eden領域

  1. Eden領域が新しいオブジェクトでいっぱいになる
  2. ScavengeGCが実行される
  3. 使用中のオブジェクト(他のオブジェクトから参照されているオブジェクト)はTo領域へと移動
  4. 参照されていないオブジェクトは破棄
  5. Eden領域がクリーンナップされ、新しいオブジェクトが入れられるようになる

To、From領域

  1. To領域に移動させられると数値「1」が割り振られる
  2. 再度Eden領域がいっぱいになり、ScavengeGCが実行されるとき、To領域とFrom領域が入れ替わる
  3. 先ほどTo領域として使われていた領域がFrom領域としてあつかわれる。
  4. ScavengeGCが実行されるたびに、From領域とEden領域のオブジェクトはTo領域に移動することになる
  5. この移動回数がカウントアップされ、
    「MaxTenuringThreshold」と呼ばれる閾値を超えるとOld領域に移動する

JVMのデフォルトのMaxTenuringThresholdは32なので、32回ScavengeGCの実行時に残ったオブジェクトはOld領域に移動する

スタック領域

ローカル変数が管理される。

ローカル変数
プログラムの一部分でしか利用できない変数
javaではメソッド内で宣言されている変数をローカル変数と呼ぶ。スコープは、その変数が宣言された場所からその変数が定義されたブロックを抜けるまで。
例としてはifやforのスコープで定義される変数。スタック変数。
  • メソッドが呼び出されたとき、Permanent領域にあるクラス情報からメソッド内容をスタック領域に展開して処理する。
  • スタック領域に積まれる単位は処理スコープ単位。
  • 処理が終わるとスコープ内の内容は破棄される。
    forやif内で宣言した変数がスコープ外で使えないのはこの為。

プリミティブ型、参照型

参考
http://www.itsenka.com/contents/development/java/class2.html
プリミティブ型
スタック領域に値が直接格納される。
参照型
スタック領域からヒープ領域のオブジェクト(newで作られたインスタンス)を参照する。値はヒープ領域に格納される。
浅いコピー shallow copy
参照型のスタック領域の部分だけコピー(ヒープ領域の値はコピーされない)
深いコピー deep copy
ヒープ領域のオブジェクトもコピーする。