160 likes | 280 Views
Java SE - Performance And Optimization [Alexander Kharichkin, NetCracker]
E N D
Java Performanceand Optimization (Оптимизация Java-кодапо быстродействию и памяти) Лекции по JavaАлександр Харичкин, Performance Support Manager, NetCracker
Why performance?Why optimize? • Нефункциональные требования (Non-functional requirements, NFR) • Отвечают на вопрос «Как должно работать то, что сделано», а не «Что должно быть сделано» • Ограничения аппаратного обеспечения • 2 High-EndServersSunFire E25k (по 72 процессора каждый, и стоимостью по 4 млн $ каждый)? • Многопользовательская нагрузка • 10? 100? 10000? • Большие объемы данных
Избегайте лишнего создания объектов // Неправильно. while(true) { byte[] buf= new byte[1024]; int count = inputStream.read(buf); if (count<0) break; //далееидетиспользованиебуффераbuf …….. } // Правильно. byte[] buf= new byte[1024]; while(true) { int count = inputStream.read(buf); if (count<0) break; //далееидетиспользованиебуффераbuf …….. }
Обнуляйте ссылки, когда они больше не нужны Объекты, ссылки на которые отсутствуют, уничтожаются «сборщиком мусора». // Неправильно. public void myMethod(){ BigObjectbigObject = new BigObject(); doSomething(bigObject); longOperation(); } // Правильно. public void myMethod() { BigObjectbigObject = new BigObject(); doSomething(bigObject); bigObject=null; longOperation(); }
Размер коллекций следует менять как можно реже • ArrayList–заполнение коллекции (не в середину), доступ по индексу. • LinkedList– добавление-удаление элементов (особенно в начало/конец). • HashSet– для быстрого определения принадлежности объекта. • TreeSet – для быстрого поиска и сортировки объектов (нужно редко). // Неправильно. List list = new java.util.ArrayList(); for(inti=0;i<10000;i++){ list.add(getNextObject()); } // Правильно. List list = new java.util.ArrayList(10000); for(inti=0;i<10000;i++){ list.add(getNextObject()); } Определяйте, какую именно коллекцию использовать конкретно для вашей задачи
Используйте при возможности поля типа static // Неправильно. public class MyClass{ private intmaximumBufferSize = 10; private Object myObject=… public Object[] createBufferAndFill(){ Object[] buf = new Object[maximumBufferSize]; Arrays.fill(buf,myObject); return buf; } } // Правильно. public class MyClass{ private staticintmaximumBufferSize = 10; private Object myObject=… public Object[] createBufferAndFill(){ Object[] buf = new Object[maximumBufferSize]; Arrays.fill(buf,myObject); return buf; } }
Повторно используйте exceptions // Неправильно. public Object myMethod(Object obj) throws Exception{ try{ ……. }catch(Exception exc){ //некоторыедействия,сопровождающие exception ……. throw new SomeException("There is a big problem"+exc); } } // Правильно. public Object myMethod(Object obj) throws Exception{ try{ ……. }catch(Exception exc){ //некоторыедействия,сопровождающие exception ……. throw new SomeException("There is a big problem", exc); } }
Используйте StringBuffer/StringBuilderвместо конкатенации строк в особо уязвимых местах // Неправильно. String result = ""; for(inti=0;i<=100;i++){ result+=""+i; } // Правильно. StringBuffersb = new StringBuffer(); for(inti=0;i<=100;i++){ sb.append(i); }
Избегайте лишних конвертацийString -> XML -> String -> XML • Пример: • Несколько классов в качестве внешнего API имеют String, а реально внутри они парсят строку и работают с ней как с XML. • В подобных случаях, метод process(Element) имеет смысл выносить в public API.
Опасайтесь String.intern Заполнение Permanent Generation Текущая реализация (в JDK 1.6 и 1.7) работает медленно при большом количестве interned строк (более 10000). Нужно чётко понимать цель вызова intern
Опасайтесь reflection • Сами по себе reflection вызовы медленнее, чем обычные • setAccessible(true) помогает, но замедление всё равно есть • В ряде случаев, вместо reflection достаточно выделить интерфейс и использовать обычные вызовы метода интерфейса. • Само обращение к reflection (findMethod, getDeclaredFields, и т.п.) обычно вызывают “string.intern” и из-за этого могут занимать ощутимое время (проценты от общего времени).
Опасайтесь wait/notify Как правило, в реальных задачах использование wait/notify не особо нужно, Но если действительно нужно, то имеет смысл смотреть в сторону java.util.concurrent.*
String.replaceAll(String regex, String replacement) • Обращайте внимание на то, что метод String#replaceAll(String regex, String replacement)проводит замену по регулярному выражению. • При этом парсинг и компиляция регулярного выражения происходит при каждом вызове replaceAll. • Так же, могут возникнуть «непонятные» ошибки, если в replacement строке встречаются символы $ или \ (см javadocк методу replaceAll).
Используйте Prepared Statement и bind-переменные Отсутствие связанных (bind) переменных приводит к рекомпиляции (hard-parse)каждого запроса на стороне сервера (СУБД) Аспект безопасности: связанные переменные гораздо более устойчивы против Code Injection
Если ничего не помогло… -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc_log.log -Xmx5m -XX:+HeapDumpOnOutOfMemoryError jstack, jmap jprof Eclipse Memory Analyzer