Oracle Java 1.7 update 6 以降では、 を使用するString.substring
と文字列の内部文字配列がコピーされ、古いバージョンでは共有されることがわかっています。しかし、現在の動作を教えてくれる公式の API は見つかりませんでした。
使用事例
String.substring
私のユースケースは次のとおりです。パーサーでは、基になる文字配列がコピーまたは共有されているかどうかを検出するのが好きです。問題は、文字配列が共有されている場合、new String(s)
メモリの問題を回避するためにパーサーが明示的に「共有解除」する必要があることです。ただし、String.substring
とにかくデータをコピーする場合、これは必要なく、パーサーでデータを明示的にコピーすることは回避できます。使用事例:
// possibly the query is very very large
String query = "select * from test ...";
// the identifier is used outside of the parser
String identifier = query.substring(14, 18);
// avoid if possible for speed,
// but needed if identifier internally
// references the large query char array
identifier = new String(identifier);
私が必要なもの
基本的に、必要がないboolean isSubstringCopyingForSure()
かどうかを検出する静的メソッドがnew String(..)
必要です。があれば検知しなくてもOKですSecurityManager
。基本的に、検出は控えめに行う必要があります (メモリの問題を回避するために、必要でなくても使用したいと思いますnew String(..)
)。
オプション
いくつかのオプションがありますが、特にOracle以外のJVMの場合、それらが信頼できるかどうかはわかりません:
String.offset フィールドの確認
/**
* @return true if substring is copying, false if not or if it is not clear
*/
static boolean isSubstringCopyingForSure() {
if (System.getSecurityManager() != null) {
// we can not reliably check it
return false;
}
try {
for (Field f : String.class.getDeclaredFields()) {
if ("offset".equals(f.getName())) {
return false;
}
}
return true;
} catch (Exception e) {
// weird, we do have a security manager?
}
return false;
}
JVM バージョンの確認
static boolean isSubstringCopyingForSure() {
// but what about non-Oracle JREs?
return System.getProperty("java.vendor").startsWith("Oracle") &&
System.getProperty("java.version").compareTo("1.7.0_45") >= 0;
}
動作の確認 2 つのオプションがあり、どちらもかなり複雑です。1 つは、カスタム文字セットを使用して文字列を作成し、部分文字列を使用して新しい文字列 b を作成し、元の文字列を変更して b も変更されているかどうかを確認することです。2 番目のオプションは、巨大な文字列を作成してから、いくつかの部分文字列を作成し、メモリ使用量を確認することです。