У нас есть большое Java-приложение (100 миллионов миллионов сообщений), которое может столкнуться с исключениями времени выполнения в любой момент - логика создается пользователями, и невозможно предвидеть каждый тип ошибки.Простым примером является NPE Null Pointer Exception, которое может произойти только для 1M из 100M записей.
Проблема заключается в том, что всякий раз, когда Java выдает исключение, оно вызывает дорогостоящий метод fillStackTrace ().В зависимости от глубины стека (временные затраты кажутся пропорциональными, а у нас глубокие стеки) снижение производительности может быть в 40 с лишним раз медленнее, чем без исключений.
Я знаю, как создавать собственные исключения и подавлять fillStackTrace (), поэтомуэто помогает, когда я могу обнаружить проблему и выдать свое собственное исключение, но я не могу понять, как встать перед чем-то вроде NPE и избежать fillStackTrace ().Я попытался манипулировать байт-кодом (нарушение безопасности, чтобы попытаться настроить Throwable), перегрузил поток и создал стек [0] в getStackTrace () (внутренняя трассировка стека выполняется в собственном коде, поэтому это не вызывается).У меня нет выбора, и мне нужна помощь.
Примечание. Заставить пользователя писать более качественные выражения нереально, у нас есть сотни пользователей (и планируют иметь тысячи), пишущих эти выражения, обратите внимание, что ониВы находитесь в Groovy, но проблема стоимости исключений не зависит, так как они происходят ниже в части стека Java.
Вот простой тест, иллюстрирующий проблему:
public class TestExceptionPerformance {
@Test
public void testMissingFieldException() {
exceptionTest(1f, 10_000_000, 100);
exceptionTest(null, 10_000_000, 100);
}
private void exceptionTest(Float value, int iterations, int stackDepth) {
long start = System.currentTimeMillis();
int exceptionCount = 0;
for (int i=0; i < iterations; i ++) {
try {
multiplyMe(value, i, stackDepth);
} catch (Throwable e) {
exceptionCount++;
}
}
System.out.println("With " + iterations + " transactions and " + exceptionCount +
" exceptions thrown at stack depth " + stackDepth + ": " +
(System.currentTimeMillis() - start) + "ms");
}
// perform multiplication deep in stack
static private float multiplyMe(Float value, int multiplier, int recurse) {
if (recurse > 0) return multiplyMe(value, multiplier, --recurse);
return value.floatValue() * multiplier;
}
}
Результаты:
С 10 000 000 транзакций и 0 исключений на глубине стека 100: 1 431 мс
С 10 000 000 транзакций и 10 000 000 исключений на глубине стека 100: 43 912 мс