Я знаю, что для Oracle Java 1.7 обновление 6 и новее при использовании String.substring
,
внутренний массив символов String копируется, а для более старых версий - общий.
Но я не нашел официального 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(..)
не требуется. Я в порядке, если обнаружение не работает, если есть SecurityManager
. В принципе, обнаружение должно быть консервативным (чтобы избежать проблем с памятью, я предпочел бы использовать new String(..)
, даже если это не обязательно).
Функции
У меня есть несколько вариантов, но я не уверен, что они надежны, особенно для JVM без Oracle:
Проверка поля 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;
}
Проверка поведения Есть два варианта: они довольно сложны. Один из них создает строку с использованием пользовательской кодировки, затем создает новую строку b с помощью подстроки, затем модифицирует исходную строку и проверяет, также ли b также изменен. Вторым вариантом является создание огромной строки, затем нескольких подстрок и проверка использования памяти.