- - PR -
staticメソッドの同時実行でメモリが破壊される?
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2007-03-02 17:38
いつもお世話になっております
先日、 定数文字列(public static final)がおかしくなる現象が発生いたしました。 その定数文字列は、下記のような実装をしています。 ------------------------------------------------------------------------------ public class MainCls extends SuperCls { public static final TEISU = StrUtil.replace(SUPER_TEISU, "B", "b") + "DEF"; <複数のメソッドを実装> } public class SuperCls { public static final String SUPER_TEISU = "ABC"; } public class StrUtil { public static String replace(String _in, String _bef, String _aft) { StringBuffer buf = new StringBuffer(_in); int index = buf.toString().indexOf(_bef); while ( index >= 0 ) { buf.replace(index, index + _bef.length(), _aft); int i = buf.toString().substring(index + _aft.length()).indexOf(_bef); if ( i >= 0 ) { index = index + _aft.length() + i; } else { index = -1; } } return buf.toString(); } ------------------------------------------------------------------------------ 上記の、 MainClsのメソッドを初回に、 別の処理より同時実行した場合、 定数TEISUは、"AbCDEF"以外の値になることはあるでしょうか? また、本件の処理のような場合に、 staticメソッドの同時実行でメモリが破壊されることはあるのでしょうか? なお、SDKは1.4.2を使用しております。 もしご存知の方がいらっしゃいましたら、 ご教授いただければ幸いです。 以上、よろしくお願いいたします。 [ メッセージ編集済み 編集者: えんぽり 編集日時 2007-03-02 18:38 ] | ||||
|
投稿日時: 2007-03-02 17:51
メモリが破壊されるわけではないですね。
初期化の順番に問題があるのではないですか? 手前味噌ですが、 http://nagise.info/java/java_static.html このあたりが参考になるかも。 | ||||
|
投稿日時: 2007-03-02 17:55
>定数TEISUは、"AbCDEF"以外の値になることはあるでしょうか?
SUPER_TEISU の値次第ではないでしょうか。 StrUtil#replace() メソッドの実装は良くみていませんが、たぶん SUPER_TEISU が "ABC" または "AbC" なのであれば TEISU は "AbCDEF" となりそうですね。 まずはコードをシンプルにして現象が発生する最小限のコードを仕立てましょう。 >staticメソッドの同時実行でメモリが破壊されることはあるのでしょうか? ないです。いくら同時に実行しようとしても、MainCls クラスがロードされたときに一度だけ初期化されるだけですから。 「メモリが破壊」されるのが物理的な現象のことを指すのであればハードウェア的な問題か、管理者の気性の問題でしょう。 ソフトウエア的な現象でしたら JVM や OS の問題かと。 [ メッセージ編集済み 編集者: インギ 編集日時 2007-03-02 17:57 ] | ||||
|
投稿日時: 2007-03-02 18:49
もしかして、SUPER_TEISU を変更して SuperClsをコンパイルし直したけど、
MainCls.TEISU に反映されない、とかいう話ですか? static final な値はコンパイル時に取り込まれてしまうので、 MailClsをコンパイルし直しさないと変更が反映されませんが。 | ||||
|
投稿日時: 2007-03-02 18:49
>nagise様
ご教授ありがとうございます。 MainClsクラスのメソッドを同時実行(仮にAとB)されたとして、 Aの実行で、MainClsクラスがロードされ、まずSELECT_SQLが生成されて、 そのタイミングでBが実行され、、、、 この場合、Bの実行はMainClsクラスがロードされるのを待たないのでしょうか。 >インギ様 大変失礼いたしました。記述ミスがありました。 SUPER_TEISUは、SuperClsクラスにて、定義されています。 (初回書き込み分は修正いたしました。) ------------------------------------------------------------ public class SuperCls { public static final String SUPER_TEISU = "ABC"; } ------------------------------------------------------------ StrUtil.replaceメソッドで、StringBufferをnewしていることがまずいのでしょうか。 staticなメソッドを同時実行する際、StringBufferをnewして使用すると、 同アドレス空間を使用するため、予期しない動作になりますか? 度々、申し訳ございません。 | ||||
|
投稿日時: 2007-03-02 18:55
>coasm様
いいえ、SUPER_TEISUは変更しておりません。 また、同様に他のPGも修正しておりません。 あるシステムにて発生した現象なのですが、 2年間、このような現象は発生しておりませんでした。 つい最近、下記の現象が発生いたしました。 なお、JVMの再起動により、現象は発生しなくなりました。 | ||||
|
投稿日時: 2007-03-02 19:56
>つい最近、下記の現象が発生いたしました。
下記、とは?? >定数TEISUは、"AbCDEF"以外の値になることはあるでしょうか? 違う値になっていることは確認できているのでしょうか? TEISU は "AbCDEF" だけども、別の部分がスレッドセーフになっていなくて TEISU が期待通りの値になっていないかのような振る舞いをしたのではないかと思います。 >staticなメソッドを同時実行する際、StringBufferをnewして使用すると、 >同アドレス空間を使用するため、予期しない動作になりますか? 少なくとも同じクラスローダ下では TEISU の初期化は一度しか行われませんので、複数のスレッドからこのクラスを呼び出しても同時実行はされませんね。 replace メソッドを同時に実行したとしても、StringBuffer buf はメソッドスコープの変数なのでそれぞれ別々のヒープ領域に配置されます。衝突することはありません。 | ||||
|
投稿日時: 2007-03-03 11:41
とくに問題ないと思います。 また、StringBuffer は言語に埋め込みではないただのひとつのクラスにすぎなかったと思います(ちょっとあやふや)ので、StrUtil などの自前のクラスと根本的に違うということもないはずです。 StringBuffer や String クラスにバグがあるのかも、という考えもできなくはありませんが、確率的にはきわめて低いのでまずは自前のクラスのほうを疑うのが自然でしょう。 あと、実際に TEISU の値が化けていたとしても、大規模なプログラム中でこれを発見できるのはかなり難しいはずです。どうしてここだと分かったのでしょうか?という疑問があります。たとえば、デバッガーで TEISU の値を表示していて化けて見えた場合は、TEISU そのものよりも、デバッガーの操作間違いやデバッガーのバグや副作用のほうを疑ったほうが良いかもしれません。 メモリーが化けることも Windows や Linux 上のプロセスですから、ソフトウェア的にはないこともないと思います。JNI を使っていたりすれば、その可能性は一気に高まります。 ハードウェア的に化けることも、ありえなくはないと思います。瞬間的な停電のようなことがあれば、確率的にはゼロではないでしょう。ただ、通常は、特定の文字列のデーター部分を狙い撃ちして化けることはまずなく、コード(命令コード)部分も化けて、プロセスが異常終了することが普通です。 -- unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86} |