web-dev-qa-db-ja.com

Stringクラスのsubstringメソッドはメモリリークを引き起こします

Stringクラスのsubstringメソッドはメモリリークを引き起こすと言われています。それは本当ですか?どうやって?その代替手段は何ですか?
特に答えを探して、
Javaでメモリリークを引き起こす可能性のある他のすべてのものは何ですか?これは、コーディング中に注意を払うのに役立ちます。

13
AmitG

JDKの過去のバージョンでは、substringメソッドの実装により、char配列全体への参照を保持する新しいStringオブジェクトが構築され、コピーが回避されていました。したがって、1つの文字列だけで非常に大きな文字配列への参照を誤って保持する可能性があります。 ここに例があります これが引き起こす可能性のあるバグの。

この方法は現在変更されており、この「リーク」はもう存在しません。

古いJDK(OpenJDK 7、Update 6より古い)を使用し、substringの後に最小限の文字列を使用する場合は、別の文字列を使用するコンストラクターを使用します。

String s2 = new String(s1.substring(0,1));

2番目の質問ですが、「Javaでメモリリークを引き起こす可能性のあるその他のこと」については、建設的な方法で答えることは不可能です。 Java標準ライブラリには、オブジェクトへの非表示の参照を簡単に保持できる場合の多くのインスタンスはありません。一般的なケースでは、作成するすべての参照に注意してください。最も頻繁な問題です。おそらく、クリーンアップされていないコレクションまたは外部リソース(ファイル、データベーストランザクション、ネイティブウィジェットなど)で発生します。

28
Denys Séguret

substring()メソッドはStringに新しい文字配列を割り当てませんが、既存にウィンドウを含むStringを生成するだけです。 char配列。これはフライウェイトパターンの実装であり、最適化と見なされていました。

したがって、巨大なString(char配列)を持っていて、部分文字列を作成した場合、元の文字列をガベージコレクションしても、元のchar配列は残ります(たとえば、次の部分文字列があると思われるにもかかわらず) 、2文字)。この問題は、(たとえば)入力データの巨大なストリーム(おそらくXMLファイル)を解析し、substring()を介して少量のテキストを抽出するときによく発生します。

一見冗長なString(String str)コンストラクター(String!をとるStringコンストラクター)を使用すると、新しい(潜在的に小さい)char配列が割り当てられ、元の配列が可能になるため、これが解決されます。収集されたゴミ。

この動作はJava 7u6の時点で変更されていることに注意してください。

12
Brian Agnew

文字列の部分文字列は、予想よりも多くのメモリを保持する可能性があります。このメモリは正常に回復できるため、メモリリークではありません。

最も簡単な解決策は、Java 7の最新バージョンを使用することです。これはこれを行いません。これはOracleから無料でサポートされている唯一のバージョンであるため、とにかくこれを行うことを検討する必要があります。

そのため、Java 7 update 5で「修正」されました。IMHOは、実装を単純化するほどの修正ではありません。すべての部分文字列のコピーを取得すると、はるかに多くの作業が必要になります。より多くのメモリを消費しますが、心配することが1つ少なくなることを意味します。

Javaでメモリリークを引き起こす可能性のある他のすべてのものは何ですか?

任意のオブジェクトをクリーンアップできるため、C/C++という用語の意味でメモリリークを作成することはできません。あなたができることは、オブジェクトを誤って保持することです。この一般的な例は、JDBCリソースなどのリソースを閉じるのを忘れていることです。これにより、予期しない方法でメモリを保持する可能性があります。

8
Peter Lawrey

Stringオブジェクトでは、substringを呼び出すと、valueプロパティが2つの文字列間で共有されます。

したがって、大きな文字列から部分文字列を取得して長期間保持すると、大きな文字列はガベージコレクションされません。実際には、メモリリークが発生する可能性があります。

5