- PR -

メモリ管理について

投稿者投稿内容
ぜんざい
会議室デビュー日: 2005/05/17
投稿数: 5
投稿日時: 2006-06-09 11:34
お世話になっております。

Javaにおけるメモリ管理について。

現在、私の中では
・java.ioのクラスにはclose()メソッドがありそれを呼び出すことで明示的に参照を終了できる
・他のクラスでは利用後にnullを代入することで明示的に参照を終了できる
・他からの参照がなければGCの対象になる
という認識です。

この認識を元にした実装例としては以下のようなコードになります。

コード:
Reader reader = null;
ArrayList list = null;

try{
    reader = new Reader();
    list = new ArrayList();
	
    //処理
	
}catch(){
    //エラー処理
}finally{
    if(list != null) list = null;
    if(reader != null){
        try{
            reader.close();
        }catch(IOException e){
            //エラー処理
        }
    }
}


会社の後輩が「ArrayListは利用後にclear()すればよいのでは?」という考えを持っていたため、
nullを代入するように勧めたのですが、そこからGCの話に行き着きました。
もともとGCについて精通している訳ではないため、調査しましたが確信が持てず
ここに書かせていただいた次第です。

私の認識、コードの記述に間違いはありますでしょうか?

識者の方々から何かご指摘をいただければ、と思っております。
よろしくお願いいたします。
ぶさいくろう
ぬし
会議室デビュー日: 2005/11/22
投稿数: 1232
お住まい・勤務地: 川崎市(は俺も含めてロクな人間が住んでないよw)
投稿日時: 2006-06-09 11:36
> 他からの参照がなければGCの対象になる
ソースにあるlistの有効範囲について考えたことある?
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2006-06-09 13:16
引用:

ぜんざいさんの書き込み (2006-06-09 11:34) より:
現在、私の中では
・java.ioのクラスにはclose()メソッドがありそれを呼び出すことで明示的に参照を終了できる
・他のクラスでは利用後にnullを代入することで明示的に参照を終了できる
・他からの参照がなければGCの対象になる
という認識です。


まず、「java.ioのクラスは」という下りですが、JVMが管理するメモリが開放される、
というより、JVMだけで管理できないリソースを明示的に開放する手段です。通常は
GCによってクラスインスタンスが開放されるのと同時にこれらのリソースも開放され
ますが、GCが発生するタイミングは制御できないため、これらのリソースが長時間
開放されないまま残るのを防ぐため、明示的にcloseなどのメソッドを呼ぶ必要があります。

下の2つは正しいです。が、nullを設定しなくても変数のスコープから外れれば、自動的
に参照も外れるので、このようなことをする必要はありません。明示的にnullを指定
する必要があるのは、変数のスコープが外れない状態でその変数が参照するオブジェクトが
不要になった場合だけです。
luckseed
常連さん
会議室デビュー日: 2006/05/23
投稿数: 24
投稿日時: 2006-06-09 13:44
>java.ioのクラスにはclose()メソッドがありそれを呼び出すことで明示的に参照を終了できる
これは間違いです。
reader.close()の後にreader.markSupported()とか呼んだらどうなると思いますか?

>他からの参照がなければGCの対象になる
これについても、少し訂正。
他から参照されている場合でも、参照元がGCの対象になった場合にはGCの対称になります。

>if(list != null) list = null;
scope抜けたら局所変数はGCの対象になるので、わざわざnullを代入する必要はありません。
代入するにしても、「nullじゃなかったら」という判別は不要ですね。

>「ArrayListは利用後にclear()すればよいのでは?」
ArrayListのclearメソッドを呼んだ場合には、ArrayList内の各要素がGCの対象になる
(もちろん他から参照されている場合は別)だけで、ArrayListのインスタンス自体はGCの対象になりません。
ゴングラッチェ
常連さん
会議室デビュー日: 2006/03/03
投稿数: 36
投稿日時: 2006-06-09 14:42
オッス!

引用:
・java.ioのクラスにはclose()メソッドがありそれを呼び出すことで明示的に参照を終了できる


ぜんざいさんの掲載ソースをみると、"reader = null;"をされていませんな。ってことは"reader.close();"をすれば、readerがnullになる(reader == null)。そういうことで"java.ioのクラスのcloseメソッドを呼ぶとで明示的に参照を修了できる"という認識をもたれたのじゃろか?この認識だったらそれはちと違いまするな。ワシが考える理由は概ねukさんが書かれているとおりじゃ。

クラスインスタンスと参照に注目すると、"reader = null;"があった方が話の筋がとおらないかの。readerだけそれをしないのは不自然じゃとワシは思う。
では、何故"reader.close();"をしたことで"reader == null"になるのか。書いてみるだに。識者の方々、優しくフォローしてくだされ。
理由・・・それは、readerが参照している"インスタンス"がJavaプログラムが管理しているものではないからじゃ。ここで言う"インスタンス"とは、OSが管理しているファイルや、別プロセスが管理しているもの(例えばOracleのDBコネクション)なんかじゃ。closeした後、Javaプログラムから見てそれら"インスタンス"は存在しなくなるじゃろ?存在しないもの参照を持つことになる。存在しない状態を表す値はnullじゃ。じゃからnullになるのじゃ。別の視点から見れば、存在しないものをあたかも存在しているかのように見える(render.close -> render != null)状況を許したら、renderのメソッドが呼ばれた時の例外処理がえらいことになるわな。インスタンスが存在しないのだから、"render == null"とし、renderを使用しようとしたら、NullPointerExceptionが発行される状況になるのが自然じゃと思うのじゃ。
何言っているのかわからんかもしれんの。心配じゃ。スレ汚しになってしまったら申し訳なし。

引用:
ukさんの書き込み 2006-06-09 13:16
GCが発生するタイミングは制御できないため


ちとコネタ。GCが発生するタイミングを制御できないかというと、そうでもないのじゃ。Javaプログラム内でGCを実行することは可能じゃ。いわゆるタイミングを制御することはできんと思うが、任意に実行することはできますじゃ。

クラス System
http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/lang/System.html
メソッドに"static void gc()"ってのがあるだに。

そうそう、個人的な意見じゃが、finally{}の中でしか後処理をしないのは好かん。確かにメソッドの最後に必ず呼ばれるわけじゃが、例外処理機構における仕組みじゃ。try{}の中でもそのスコープにおける後処理があってしかるべきじゃと思う。なんでもfinallyで後処理せんで、適宜後処理を入れる方がワシは好みじゃ。finally{}内には"解決しておかなければならん事"のみを書いてあげるのが例外処理機構におけるfinallyの正しい使い方じゃと思う。「無駄じゃん」とか「便利だからいいじゃん」意見が多く出るだろうし、それは有りじゃよ。

スコープを抜けると確かに変数がなくなるわいな。しかし後処理として変数にnullを代入する行為は良いことじゃと思う。有効期間を意識したプログラムを描くことは良いことじゃ。前処理、主処理、後処理をキチッとやる。その努力、習慣は不注意によるバグを防ぐころじゃろうて。気張りぃや。

[ メッセージ編集済み 編集者: ゴングラッチェ 編集日時 2006-06-09 14:52 ]
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2006-06-10 00:36
引用:

ゴングラッチェさんの書き込み (2006-06-09 14:42) より:
ちとコネタ。GCが発生するタイミングを制御できないかというと、そうでもないのじゃ。Javaプログラム内でGCを実行することは可能じゃ。いわゆるタイミングを制御することはできんと思うが、任意に実行することはできますじゃ。

クラス System
http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/lang/System.html
メソッドに"static void gc()"ってのがあるだに。


System.gc()を読んだからといって必ずしもガーベッジコレクタが
動くわけではないのですが、通常は動くようですね。
(リアルタイムJavaプログラミング ISBN:4-89471-743-3 24Pより)
結局のところガーベッジコレクタの挙動というのはVMの実装依存で、
System.gc()はガーベッジコレクタの起動を促すが、
最終的にはVMの実装によるということだったかと。
(重箱の隅のような話で申し訳ありません)

finallyでnullを入れる話は一概には否定できないのですが、
ukさんもおっしゃってるとおり、ローカル変数はスコープを外れれば、
どこかのフィールドに設定するとかreturnで参照をメソッド外に渡すとかいう
特殊事情がない限りは確実に消滅しますので、使い終わった変数にnullを、
という習慣をつけるよりも、変数を宣言する際はスコープを極力小さくする
習慣をつけるほうが実りがあるように思います。

実際、スコープが最小限となっていれば、それこそnullを代入しようかと
いうタイミングこそはスコープの終端となるはずで、変数は生きているけど
中身が使われないという状況を抑えることができると思います。
だらだらと行数の多いメソッドを書いてしまった場合はnullを代入というのは
効果が現れるかと思いますが、そもそも構造化をしましょうよ、ということで。

ioのclose()の話は答えはすでに出ていますね。
ゴングラッチェ
常連さん
会議室デビュー日: 2006/03/03
投稿数: 36
投稿日時: 2006-06-10 12:12
オッス!
nagiseさんSystem.gc()についてフォローありがとうございます。変数にnullを代入する習慣よりもスコープを極力小さくする習慣をつけるほうが実りがあることについて、この書き込みを見て"ごもっともじゃ"と思いました。
処理の単位と構造化をどこまでやるかが勘所ですな。DBにおける正規化のように適度に行う・・・なんて話し始めたらこのスレの趣旨から外れていってしまいますな。スレの趣旨に対する回答はおおかた出たかと。ワシはスレ主待ちにします。ほな、またいずれ。
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2006-06-10 22:40
引用:

ゴングラッチェさんの書き込み (2006-06-09 14:42) より:
では、何故"reader.close();"をしたことで"reader == null"になるのか。書いてみるだに。識者の方々、優しくフォローしてくだされ。
closeした後、Javaプログラムから見てそれら"インスタンス"は存在しなくなるじゃろ?存在しないもの参照を持つことになる。存在しない状態を表す値はnullじゃ。じゃからnullになるのじゃ。別の視点から見れば、存在しないものをあたかも存在しているかのように見える(render.close -> render != null)状況を許したら、renderのメソッドが呼ばれた時の例外処理がえらいことになるわな。インスタンスが存在しないのだから、"render == null"とし、renderを使用しようとしたら、NullPointerExceptionが発行される状況になるのが自然じゃと思うのじゃ。


自然だけどそうはなっていないことを嘆いてるんでしょうか?
それともcloseを実行するとnullになるのを事実と思って書いてるんでしょうか?
そんな動作は初耳です。

スキルアップ/キャリアアップ(JOB@IT)