メモリリークの発生時の条件とdisposeメソッドの使い方

このQ&Aのポイント
  • メモリリークはメモリが解放されずに残るケースであり、画面のCloseやセッションタイムアウトなどでメモリが解放されるが、その他の条件ではメモリリークが発生する可能性がある。
  • クラスのコンストラクタでメモリが確保され、親オブジェクトが解放されると自分自身のメモリも解放される。スタティックメソッドで参照渡しの引数がある場合は、オブジェクトのポインタが渡され、処理完了後に解放される。
  • 画面右上の×ボタン以外で画面が閉じても、セッションタイムアウト時にはメモリが解放される。disposeメソッドはメモリリークを防ぐために用いられるが、特定の条件で使用する必要があり、必ずしも全ての箇所で使用する必要はない。
回答を見る
  • ベストアンサー

メモリリークが発生するのはどういうときですか?

メモリが解放されずに残るケースというのは、どういうときがあるのでしょうか? ※asp.netでプログラムを書いています。 (1)どのクラスも、基本的にコンストラクタでメモリが確保され、 どのクラスも、その親のオブジェクトが解放されたら、自分自身のメモリも解放される。 よって、画面のCloseで、すべてのオブジェクトのメモリは解放される。と思っています。 (2)スタティックメソッドで、参照渡しの引数があるとき、何度そのメソッドを使っても、 オブジェクトのポイントが渡るだけだし、処理完了後は、そのポインタすらも解放すると思っています。 (3)画面右上の「×」のボタン以外で画面が閉じてしまったとしても、セッションタイムアウトになった時点で、その分のメモリは解放すると思っています。 ◆どうしてdisposeメソッドがあるのでしょうか? .自分は、プログラム内に1箇所もdisposeを書く必要がないと思っていますが、どのような時に使うべきなのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

メモリの確保はnew演算子のタイミングです (コンストラクタではありません)。 staticなフィールドに関しては,別のタイミングになります。 また,解放されるのは, ・そのインスタンスへの全てのルート参照から(強)参照で辿るためのパスが存在しない ・該当世代のガベージコレクションが実行された の両方を満たすタイミングです。 # ファイナライザがあると,解放が1世代遅れます。 で,staticなフィールドはルート参照であり,そこから(強)参照で辿れるインスタンスは,解放されることがありません。 クラスTのstaticなフィールドにList<T>を用意し,TのコンストラクタでそのフィールドにthisをAddしているような場合に相当します。 staticなフィールドから辿れるインスタンスは,明示的にListからRemoveするなり,nullを代入するなりして,参照を辿れなくする必要があります。 ASP.NETにおけるメモリリークは,これが一番の原因になると思います。 IDisposable.Disposeメソッドは,インスタンスの後処理を行うためのメソッドです。 主に,メモリ以外のリソースの解放処理を行います。 ファイルやネットワーク,DBコネクションなどはGCのタイミングで解放されたのでは遅いことが多いため,Disposeを呼び出します。 なお,通常はusing文を使ってIDisposable.Disposeを確実に呼び出すことが出来るようにします。

souken_200
質問者

お礼

try...finallyよりも、usingの方がシンプルなソースになるので、そっちを調べてみました。 ◆ファイル,ネットワーク,DBコネクションなどのときは、 Dim s As String Using sr As New System.IO.StreamReader( _ "C:\test.txt", System.Text.Encoding.GetEncoding(932)) s = sr.ReadToEnd() End Using Console.WriteLine(s) のようにしようと思います。 ありがとうございます!

その他の回答 (2)

  • wormhole
  • ベストアンサー率28% (1621/5657)
回答No.3

(1)「その親のオブジェクトが解放されたら」と書かれていますが、その親のオブジェクトが解放されるのはいつですか。 (2)解放されるタイミングは処理完了後ではありません。 (3)ASP.NETならクライアント側の画面は関係ありません。

souken_200
質問者

お礼

調べる良いきっかけになりました。ありがとうございます。

souken_200
質問者

補足

(1),(2) 親オブジェクトが、 ApplicationStartでnewされたなら、生きているのはApplicationEndまででしょうし、 SessionStartでnewされたものは、生きているのはSessionEndまででしょうし、 画面が開かれた際に作られる、画面上のオブジェクトは、画面が閉じられるまでという認識です。 画面のCloseが適正にハンドルできなかった場合などは、SessionTimeOutで消えると思っています。

  • WebSurfer
  • ベストアンサー率55% (33/59)
回答No.1

.NET アプリのランタイムにはガベージコレクタが備わっているので、サーバー側ではメモリリークよりコネクションリークが問題になると思います。詳しくは以下のページを参照してください。Dispose メソッドについても書かれています。 .NETの例外処理 Part.2 http://blogs.msdn.com/b/nakama/archive/2009/01/02/net-part-2.aspx ブラウザ側では循環参照がメモリーリークの原因として一番多いのではないかと思います。詳しくは以下のページを見てください。 Internet Explorer リーク パターンを理解して解決する http://msdn.microsoft.com/ja-jp/library/bb250448(v=vs.85).aspx

souken_200
質問者

お礼

ガベージコレクタ様々ですね。 メモリ以外のリソースの割り当てと管理は、usingで行おうと思います。 ブラウザ側は、単純にデータを表示しているだけなので、今回は問題なさそうです。 ありがとうございます。

関連するQ&A

  • ◆コピコンを実装しないと、returnでエラー?

    ポインタを持ったクラスで、 コピーコンストラクタを実装していないと、 newを使用した際にエラーになるそうですが、 なぜなのでしょうか? 値渡しの関数などで、 コピーコンストラクタを実装していないと、 デフォルトコピーコンストラクタで、ポインタ型のメンバ変数の値もコピーするため、 return する前に、 「一時的な変数としてコピーされていた値渡しの引数」が、 関数の終了時に解放され、 「アドレスを指しているポインタ」が指し示す先の領域に「delete」が走ってしまうため、 呼び元の変数で持っているポインタが指し示す先の領域も、 解放されてしまうとかでしょうか?? そもそも、 ポインタ pMem=NULL は、アドレスの指し示す値のリセットで、 Delete pMem は、アドレスが指し示す先頭から、そのクラスで必要としている分のメモリ量進んだアドレスまでを、解放する。 ということで合っているでしょうか? それとも、 「ポインタ」を削除しても、ポインタの指し示す先のアドレス自体は存在していて、 「呼び元」のアドレス格納用領域と、 「関数の呼び出し時にコピーコンストラクタで作られるアドレス格納用領域」は別であり、 ポインタ自体を削除しても、ポインタの先にあるメモリ領域は残っているのでしょうか?

  • JAVAにおけるメモリリーク

    クラスAの中でクラスBがnewされているとき、 クラスAの参照をnull にセットしさえすれば、 内包されているクラスBに確保したメモリも即時に解放されるのでしょうか? それともガーベジコレクションにてどこからも参照されていないことがわかった時点で解放されるのでしょうか? はたまた解放されないのでしょうか? ClassA {  ClassB instanceX = new ClassB(); } - - - - - - - - - - - - - - - - - - - - - - - - new をした際、そのメソッドの最後や、 Exceptionのキャッチ後のthrow前に、 変数 = null; は書いていますが、 これ以外ではどういう点に気をつければ良いかがわかっていません。 どういうときにJavaでメモリリークが起こるのでしょうか?

    • ベストアンサー
    • Java
  • 関数で値渡しと参照渡しではどっちがメモリを使うのか

    クラスAの大きなサイズのオブジェクトを、 クラスBで処理するメソッドを書こうとしています。 ◆質問 このとき、クラスBでは、byval で記載するのと、byrefで記載するのでは、 どちらの方がメモリを食わないのでしょうか? ◆自分の想定 (1)byrefで記載した場合、そのオブジェクトのポインタを受け取って処理するため、あんまりメモリは食わない。 (2)byvalで記載した場合、ある意味、.clone のような処理がされて、渡されたオブジェクトと同じサイズのメモリを食う? ※処理しようとしていることは、特に参照渡しされた変数の値を修正するような類ではないです。 なので、「オブジェクトを不用意にいじってしまう危険性」などの観点は無視し、メモリの観点の話です。 ちなみに、メソッドを、shareで宣言しようが、インスタンス化してからじゃないと使えないように宣言しようが、その関数のために使用されるメモリのサイズ(※クラスBのインスタンス化のためのメモリではないという意味)は変わらないということで合っていますでしょうか? .

  • リフレクション

    Webアプリ上でリフレクションにてとあるクラスのメソッドを実行するサンプルを作成して 見たのですがうまく動きませんでした。最後のmethod.invoke()の処理にてExceptionが発生し、 java.lang.IllegalArgumentException: object is not an instance of declaring class と表示されてしまいます。 作成したサンプルは下記なのですがどこが原因かお分かりになりますでしょうか。 try { Class cls = Class.forName("dao.TestDao"); // 引数の型をセット Constructor constructor = cls.getDeclaredConstructor(HttpSession.class); constructor.setAccessible(true); // 引数を渡してオブジェクトを生成 Object obj = constructor.newInstance(session); Method method = cls.getDeclaredMethod("getDataDao", int.class); method.setAccessible(true); Object result = method.invoke(cls, new Integer(100)); } catch (Exception e) { e.printStackTrace(); } // このクラスのgetDataDao()をリフレクションにて実行 public class TestDao { HttpSession session = null; public TestDao(HttpSession session) { this.session = session; } public List<String> getDataDao(int iNo) { List<String> list = new ArrayList<String>(); list.add((String)session.getAttribute("1")); list.add((String)session.getAttribute("2")); list.add((String)session.getAttribute("3")); list.add((String)session.getAttribute("4")); list.add((String)session.getAttribute("5")); return list; } }

    • ベストアンサー
    • Java
  • メソッドの引数としてのthisの意味

    java初心者です。教えてください。 メソッドの引数としてのthisは何を表しているのですか? いろいろ調べてみてthisには以下の2つの使用法があることがわかりました。 1.インスタンス変数の名前とインスタンスメソッド内のローカル変数名がかぶったときに、メソッド内でインスタンス変数を表すときにthis.変数名とする。 2.あるクラスのコンストラクタ内で、同じクラスの別のコンストラクタを呼ぶときに使う。 しかし、引数としてのthisの意味がわかりません。 具体的には、addMouseListener(this);や、g.drawImage(img,10,10,this);のthisです。 後者の場合はオブジェクトgのインスタンスメソッドなので、thisはオブジェクトgへの参照を表しているのでしょうか?

    • ベストアンサー
    • Java
  • オブジェクト生成時のセオリーについて

    オブジェクト指向を採用しているプログラミング言語において、ほとんどの場合、オブジェクト生成時に使用されるコンストラクタは返り値を持てません。 また、コンストラクタにて例外を投げるといったことは推奨されていないケースが多いです。 そんな中で、コンストラクタに何らかの引数を渡してインスタンスを生成するクラスの場合、不十分な引数を渡すことで使用できない状態となるインスタンスが生成されることがあります。 こういったことを踏まえて、渡される引数が適しているものであることを確認する役割というのは使用されるクラス自身が担うのか、クラスを生成する外部の処理(ファクトリー的なクラス・メソッド)が担うのか、どちらが一般的なセオリーなんでしょうか? 無論、不十分なインスタンスが誤って使用されないようにメソッドにエラー処理をかけ、「使用できない状態のオブジェクトである」ことを通知するのは当然なのでしょう。 ただ、最近知り合いから「クラスはできるだけ不変な状態を保つよう設計した方がいい。そのほうが使いやすく、再利用時のバグが減る」という話を聞いて状態を持たないクラスの設計というのを考えこんでしまい、悩んでいます。 わかりにくい質問かもしれませんが、回答よろしくお願いします。

  • delete演算子によるメモリ解放について

    MFC MDIプログラミングで、 Genericクラスで点、線、面クラスを作って、 オブジェクトを組み合わせて 3次元図形を作っています。 図形を削除する際、 delete演算子で各オブジェクトの メモリ解放をプログラムしています。 例) delete m_pLine; delete m_pSurface; しかしながら、これらポインタの中には、 アルゴリズム上、既にdeleteされているものもあるため、 既にdeleteしたオブジェクトを更に deleteしようとして 実行時エラーを生じてしまいます。 deleteする前に、 当該ポインタが既にdeleteされているかどうか 判定する関数等あれば if文で回避できると思うのですが、 何か良い方法がありますでしょうか? よろしくお願いします。

  • DBを扱う上でのclose()メソッドの必要性

    JavaでDBにアクセスする為の勉強中です。 使用しているクラスは Connection、Statement、ResultSet でそれぞれfinallyの部分でclose()メソッドを呼んでいます 例えばこのときStatementのJavaDocでclose()メソッドの説明を読むと >自動的にクローズされるときに Statement オブジェクトのデータベースと JDBC リソースが解放されるのを待つのではなく、ただちにそれらを解放します。 とあり、該当のメソッドを呼ばなくても、リソースは解放されるようですが、ただちに解放する必要性はどこにあるのでしょうか? 検索結果で表示されるサイト等も大半はclose()が書かれていますが、 おまじない的な話しか載ってるのを見る程度でした。

  •  superについて教えて下さい

     superについて教えて下さい  JAVAの初心者です、宜しくお願いします。  「super」についてよくわかりません。 ある本には、「親クラスのコンストラクタを呼び出す」、またある本には、「親クラスのオブジェクトを呼 び出す」、と書かれていました。  ・コンストラクタとオブジェクトとは同じ意味なのでしょうか。  ・また、ある本には、「コンストラクタの継承はされない」とかかれていますが、どのように違うのでしょうか。  ・JAVAのApIには、次のように書かれています。   「paint     public void paint(Graphics g)コンテナをペイントします。このコンテナの子コンポーネントで    あるすべての軽量コンポーネントへペイント要求を転送します。このメソッドが再実装される場合、軽量    コンポーネントが正しく描画されるように super.paint(g) を呼び出さなければなりません。    (以下略)」   super.paint(g)と各意味は、親クラスのメソッドを呼びだすことで、親クラスのメソッドを呼びだす時に  も、superが必要ということでしょうか。  コンストラクタ自体についてよく理解出来ていないのですが  ・そもそもクラス(オブジェクトの生成)にとってどのような役割、意味があるのでしょうか。   オブジェクトの生成すると、デフォルトで自動的に引数なしのコンストラクタが作成されると書かれています  が、  ・作成されること自体にどのような意味があるのでしょうか。  変数の初期化とかをコンストラクタ内で設定するのは意味があるとは思うのですが、、、、

    • ベストアンサー
    • Java
  • Webアプリのメモリリーク

    Webアプリをjavaで開発しておりTomcat7を使用しています。 Windowsタスクマネージャーで tomcat7.exe のプロセスが使用するメモリを監視していたところ tomcat起動時には80Mほどの使用量なのですがWebアプリを使っているうちに150Mほどに 上昇します。 その後、使用し続けてもほとんど上昇しないのですがログアウトしてもメモリ使用量が150Mほど のままで変化がありません。 これはメモリリークしているのでしょうか。ログアウト時にはセッションはinvalidate()メソッドにて 無効化しています。 ログアウトすると初期の80Mほどにメモリ使用量が変化すると思っていたのですが まだ何かオブジェクトへの参照が残っているということでしょうか。30分ほど放っておけば ガーベッジコレクションされるのかと思ったのですがメモリ使用量が変わらなかったので ガーベッジコレクションされてるわけでもなさそうです

    • ベストアンサー
    • Java

専門家に質問してみよう