getStackTrace() 依存のソースコードは書かない方がいいんじゃないかなー
同僚が書いたソースコードにスタックトレースから呼び出し元クラスを取得して動作を変えるような処理を発見。うーん、よろしくない気がする。
/** * Provides programmatic access to the stack trace information printed by * {@link #printStackTrace()}. Returns an array of stack trace elements, * each representing one stack frame. The zeroth element of the array * (assuming the array's length is non-zero) represents the top of the * stack, which is the last method invocation in the sequence. Typically, * this is the point at which this throwable was created and thrown. * The last element of the array (assuming the array's length is non-zero) * represents the bottom of the stack, which is the first method invocation * in the sequence. * * <p>Some virtual machines may, under some circumstances, omit one * or more stack frames from the stack trace. In the extreme case, * a virtual machine that has no stack trace information concerning * this throwable is permitted to return a zero-length array from this * method. Generally speaking, the array returned by this method will * contain one element for every frame that would be printed by * <tt>printStackTrace</tt>. * * @return an array of stack trace elements representing the stack trace * pertaining to this throwable. * @since 1.4 */ public StackTraceElement[] getStackTrace() { return (StackTraceElement[]) getOurStackTrace().clone(); }
スタックトレースは元々、vm によって、出たり出なかったりするような情報。
(実際問題、今回ターゲットとしている本番環境の vm では出ないと思われる)
それに、ターゲットは、Java5 なんで、sun の vm を使用したって問題がある。
Bug ID: JDK-6751861 Memory leak occurs in JVMTI(jdk5.0u16)
getStackTrace() のメモリリーク報告。
こちらで根本対応
Bug ID: JDK-6306746 Add assertions to GrowableArray and ResourceObj
GrowableArray 使用時のリークの問題。今後はこういう風に書いてね、と。
GrowableArray<T> *ga = new (C_HEAP) GrowableArray<T>(,true); ... delete ga; // call dtor and ResourceObj::operator delete()
メモリリークする問題は、JDK 5.0 Update 18 に修正版が入るみたい。(2009/3/12 時点ではまだリリースされていない)
ただ、上記のような問題が仮になかったとしても、頻繁に呼ばれるような処理の中で使うようなもんではないだろう。getStackTrace() の内部処理はスタックへのポインタを取得するといったような、軽い処理ではない。
内部でスタックをガッサリコピーして渡しているのだ。
インターフェイスが変わっちまうので避けたのだと思うんだけど、呼び出し元クラスによって処理を分けたいだけなんで、
public void method(Class<?> invoker, ...)
等として、呼び出し元クラス側にセットさせた方が手堅いような気がするんだけどなー。