Оптимизировать программы с помощью спецификаций кода Java, оптимизировать использование памяти и предотвратить утечку памяти
Ресурсы, доступные для программ для использования (память, время процессора, пропускная способность сети и т. Д.). Оптимизация обычно включает в себя два аспекта: уменьшение размера кода и повышение эффективности работы кода. В этой статье в основном обсуждается, как повысить эффективность кода.
В программах Java большинство причин проблем производительности не на языке Java, а в самой программе. Очень важно разработать хорошие привычки написания кода, такие как правильно и умно применять класс java.lang.string и класс java.util.vector, что может значительно улучшить производительность программы. Давайте подробно проанализируем эту проблему ниже.
1. Попробуйте указать, что окончательный модификатор класса.
В Java Core API есть много примеров применения финала, таких как java.lang.string. Указание окончания для класса строки предотвращает перезапись метода длины (). Кроме того, если класс указан как окончательный, все методы этого класса являются окончательными. Компилятор Java будет искать возможности для внедрения всех окончательных методов (это связано с конкретной реализацией компилятора). Этот шаг может повысить производительность в среднем на 50%.
2. Попробуйте повторно использовать объект.
Особенно при использовании строковых объектов stringbuffer используется вместо этого, когда происходит конкатенация строки. Поскольку система не только требует времени, чтобы сгенерировать объекты, но также может потребоваться время для сбора мусора и обработки этих объектов в будущем. Следовательно, создание слишком большого количества объектов окажет большое влияние на производительность программы.
3. Постарайтесь использовать локальные переменные.
Другие переменные, такие как статические переменные, переменные экземпляра и т. Д., Созданы в куче и медленнее. Кроме того, локальные переменные могут быть дополнительно оптимизированы в зависимости от конкретного компилятора/JVM. См. «Используйте переменные стека, когда это возможно».
4. Не повторяйте инициализацию переменных <br /> по умолчанию, при вызове конструктора класса Java будет инициализировать переменную до определенного значения: все объекты устанавливаются на NULL, целочисленные переменные (байт, короткий, Int, Long) SET SET Для 0, плавание и двойные переменные установлены на 0,0, а логические значения устанавливаются на FALSE. Это должно быть особенно замечено, когда класс получен из другого, потому что, когда объект создается с новым ключевым словом, все конструкторы в цепочке конструктора называются автоматически.
5. При разработке системы приложений Java + Oracle попробуйте использовать форму верхней регистрации в Java, чтобы уменьшить бремя синтаксического анализа синтаксика Oracle.
6. Во время программирования Java будьте осторожны при выполнении подключений к базе данных и потоковой передачи ввода/вывода.
Поскольку работа этих больших объектов вызовет накладные расходы на большие системы, и если вы не будете осторожны, это приведет к серьезным последствиям.
7. Поскольку JVM имеет свой собственный механизм GC, он не требует слишком большого рассмотрения разработчиков программ, что в определенной степени снижает бремя для разработчиков, но также пропускает скрытые опасности. В системе .
Условие JVM для переработки мусора заключается в том, что объект не ссылается; Поэтому рекомендуется, чтобы мы вручную установили его на NULL после использования объекта.
8. При использовании механизма синхронизации попробуйте использовать синхронизацию метода вместо синхронизации блока кода.
9. минимизировать повторные расчеты переменных <br /> Например: для (int i = 0; i <list.size; i ++) {
…
}
Следует заменить на:
for (int i = 0, int len = list.size (); i <len; i ++) {
…
}
10. Попробуйте принять ленивую стратегию загрузки, то есть начать создавать при необходимости.
Например: string str = «aaa»;
if (i == 1) {
list.add (str);
}
Следует заменить на:
if (i == 1) {
String str = «aaa»;
list.add (str);
}
11. Используйте аномалии с осторожностью
Аномалия не подходит для производительности. Чтобы сделать исключение, вы должны сначала создать новый объект. Конструктор брошенного интерфейса вызывает локальный (нативный) метод с именем filinstacktrace (), а метод filinstacktrace () проверяет стек и собирает информацию о следах вызова. Пока исключение брошено, виртуальная машина должна настроить стек вызовов, потому что при обработке создается новый объект. Исключения могут использоваться только для обработки ошибок и не должны использоваться для управления потоком программ.
12. Не используйте его в цикле:
Пытаться {
} ловить() {
}
Это должно быть помещено на самый внешний слой.
13. Использование StringBuffer:
StringBuffer представляет переменную, записываемую строку.
Есть три метода строительства:
StringBuffer ();
StringBuffer (int size);
StringBuffer (String Str);
Конструктор, упомянутый здесь, является StringBuffer (int Length), а параметр длины указывает количество символов, которые может удерживать текущий StringBuffer. Вы также можете использовать метод EncureCapacity (int Minimum емкость) для установки его емкости после создания объекта StringBuffer. Во -первых, давайте посмотрим на поведение StringBuffer по умолчанию, а затем найдем лучший способ повысить производительность.
StringBuffer поддерживает массив символов. Когда StringBuffer достигнет своей максимальной емкости, он увеличит свою емкость в 2 раза превышает текущую емкость и добавит 2, то есть (2*Старое значение +2). Если вы используете значение по умолчанию, после инициализации, тогда добавьте его символы. до 70 (2*34+2). Независимо от того, что, пока StringBuffer достигает своей максимальной емкости, он должен создать новый массив символов, а затем переоценить как старых, так и новых символов. Следовательно, не ошибочно устанавливать разумное значение емкости инициализации для StringBuffer, которое принесет немедленное усиление производительности. Это показывает роль регулировки процесса инициализации StringBuffer. Таким образом, использование подходящего значения емкости для инициализации StringBuffer всегда является оптимальным предложением.
14. Используйте Java Class java.util.Vector разумно.
Проще говоря, вектор - это массив экземпляров java.lang.object. Вектор аналогичен массиву, и его элементы могут быть доступны через индекс в виде целого числа. Однако после создания объекта векторного типа размер объекта может быть расширен и уменьшен в зависимости от добавления или удаления элементов. Пожалуйста, рассмотрите следующий пример добавления элементов к вектору:
Object bj = new Object ();
Вектор V = новый вектор (100000);
для (int i = 0;
I <100000;
Если не существует абсолютно достаточной причины для того, чтобы потребовать новых элементов были вставлены перед вектором каждый раз, вышеупомянутый код является плохим для производительности. В конструкторе по умолчанию первоначальная емкость вектора составляет 10 элементов. Векторный класс похож на класс объекта StringBuffer. Следующий фрагмент кода на порядок быстрее, чем в предыдущем примере:
Object bj = new Object ();
Вектор V = новый вектор (100000);
для (int i = 0; i <100000; i ++) {v.add (obj);
То же правило относится к методу remove () векторного класса. Поскольку каждый элемент в векторе не может содержать «пространство» между каждым элементом, удаление любого другого элемента, за исключением последнего элемента, вызывает элементы после удаления удаленного элемента вперед. То есть удаление последнего элемента из вектора в несколько раз меньше «накладных расходов», чем удаление первого элемента.
Предполагая, что мы хотим удалить все элементы из предыдущего вектора, мы можем использовать этот код:
для (int i = 0; i <100000; i ++)
{
v.remove (0);
}
Однако по сравнению со следующим кодом, предыдущий код превышает порядки медленнее:
для (int i = 0; i <100000; i ++)
{
v.remove (v.size ()-1);
}
Лучший способ удалить все элементы из объекта V вектора типа:
v.RemovealLelements ();
Предположим, что объект V вектора типа содержит строку «Привет». Рассмотрим следующий код, который удаляет строку «Привет» из этого вектора:
String s = "hello";
int i = v.indexof (s);
if (i! = -1) v.remove (s);
Код выглядит как ничего плохого, но он также плохо для производительности. В этом коде метод indexof () ищет V в последовательности, чтобы найти строку «привет», а метод удаления (S) также должен искать в том же порядке. Улучшенная версия:
String s = "hello";
int i = v.indexof (s);
if (i! = -1) v.remove (i);
В этой версии мы непосредственно даем точную позицию индекса элемента, который будет удален в методе remove (), тем самым избегая второго поиска. Лучшая версия:
String S = "Hello";
Наконец, давайте посмотрим на фрагмент кода о векторном классе:
для (int i = 0; i ++; i <v.length)
Если V содержит 100 000 элементов, этот фрагмент кода позвонит методу v.size () 100 000 раз. Хотя метод размера является простым методом, он по -прежнему требует накладных расходов вызова метода, по крайней мере, JVM должен настроить и очистить среду стека для него. Здесь код внутри цикла не будет изменять размер объекта V векторного типа V, поэтому приведенный выше код лучше всего переписывается в следующую форму:
int size = v.size ();
Хотя это простое изменение, оно все еще выигрывает производительность. В конце концов, каждый цикл ЦП является драгоценным.
15. При копировании большого количества данных используйте команду System.ArrayCopy ().
16. Рефакторинг кода: улучшить читаемость кода .
Например:
Общедоступный класс ShopCart {Private List Carts;… public void Add (Object Item) {if (carts == null) {carts = new ArrayList ();} crts.add (item);} public void remove (Object Item) {Если (Carts. Содержит (item)) {carts.remove (item);}} public list getCarts () {// return return stirt-ytonly return collections.unmodifiablelist (carts);} // Этот метод не рекомендуется // Это . 17. Создайте экземпляр класса без использования новых ключевых слов
При создании экземпляра класса с новым ключевым словом все конструкторы в цепочке конструктора будут вызваны автоматически. Но если объект реализует клонируемый интерфейс, мы можем вызвать его метод Clone (). Метод Clone () не вызывает каких -либо конструкторов класса.
При использовании шаблона проектирования, если вы используете заводский режим для создания объекта, очень просто использовать метод Clone () для создания нового экземпляра объекта. Например, ниже приводится типичная реализация заводской шаблона:
публичный статический кредит getNewCredit () {
вернуть новый кредит ();
}
Улучшенный код использует метод Clone () следующим образом:
Частный статический кредитный базовый базовый уровень = новый кредит ();
публичный статический кредит getNewCredit () {
возврат (кредит) basecredit.clone ();
}
Приведенная выше идея также очень полезна для обработки массива.
18. Умножение и деление
Рассмотрим следующий код:
for (val = 0; val <100000; val += 5) {
alterx = val * 8;
}
Замена умножения с помощью операций смены может значительно улучшить производительность. Вот измененный код:
for (val = 0; val <100000; val += 5) {
alterx = val << 3;
}
Модифицированный код больше не умножается на 8, а вместо этого использует эквивалентную левую сдвиг в 3 бита, с 1 битом на левый сдвиг, эквивалентный для умножения на 2. Соответственно, правая сдвиг на 1 -битную операцию эквивалентно делениям на 2. Стоит отметить, что, хотя операция смены быстро, она может затруднить понимание кода, поэтому лучше добавить некоторые комментарии.
19. Закрыть бесполезные сессии на странице JSP.
Распространенное недопонимание заключается в том, что сеанс создается, когда есть клиент. , используйте <>, чтобы закрыть его. Поскольку сеанс потребляет ресурсы памяти, если вы не планируете использовать сеанс, вы должны закрыть его во всех JSP.
Для страниц, которым не нужно отслеживать статус сеанса, закрытие автоматического создания сеансов может сохранить некоторые ресурсы. Используйте директиву следующей страницы: <%@ page session = "false"%>
20. JDBC и I/O
Если приложению необходимо получить доступ к крупномасштабному набору данных, вам следует рассмотреть возможность использования извлечения блоков. По умолчанию JDBC каждый раз извлекает 32 строки данных. Например, предположим, что мы хотим пройти набор записей из 5000 строк, JDBC должен вызвать базу данных 157 раз, прежде чем он сможет извлечь все данные. Если размер блока изменяется на 512, количество вызовов в базу данных будет уменьшено до 10 раз.
21. Сервлет и использование памяти <br /> Многие разработчики сохраняют большое количество информации для пользовательских сеансов по желанию. Иногда объекты, хранящиеся в сеансе, не переработаны механизмом сбора мусора во времени. С точки зрения производительности типичным симптомом является то, что пользователь считает, что система периодически замедляется, но не может приписывать причину какому -либо конкретному компоненту. Если вы следите за пространством кучи JVM, оно проявляется как аномальные колебания использования памяти.
Есть два основных способа решения этой проблемы памяти. Первым методом является реализация интерфейса httpsessionBindingListener во всех бобах с объемом сеанса. Таким образом, до тех пор, пока реализован метод valueUnbound (), ресурсы, используемые бобами, могут быть явно опубликованы.
Другим способом является аннулировать сессию как можно скорее. Большинство серверов приложений имеют возможность установить интервал недействительной сеанса. Кроме того, метод сеанса SetMaxInactiveInterval () также может быть вызван программным образом.
22. Используйте следы буфера
Некоторые серверы приложений имеют добавленную функцию маркировки буфера для JSP. Например, Bea's Weblogic Server поддерживает эту функцию со времен версии 6.0, а проект Open Symphony также поддерживает эту функцию. Bufpering Tags JSP может буферизировать как фрагменты страниц, так и всю страницу. Когда страница JSP выполняется, если целевой фрагмент уже находится в буфере, код, который генерирует фрагмент, больше не нужно будет выполнять. Буферизация на уровне страниц отражает запросы на указанный URL и буферизирует всю страницу результатов. Эта функция чрезвычайно полезна для корзин для покупок, каталогов и домашних страниц портала. Для таких приложений буферизация на уровне страницы может сохранить результаты выполнения страницы для последующих запросов.
23. Выберите правильный механизм цитирования
В типичной системе применения JSP заголовок и части нижнего колонтитула часто извлекаются, а затем заголовок и нижний колонтитул вводятся по мере необходимости. В настоящее время существует два основных метода внедрения внешних ресурсов в страницы JSP: включить директивы и включать действия.
Включите директиву: например, < %@ include file = "copyright.html" %>. Эта директива представляет указанный ресурс во время компиляции. Перед компиляцией страница с директивой включает и указанный ресурс объединяется в файл. Внешние внешние ресурсы, приведенные в соответствии с временем компиляции, что более эффективно, чем определение ресурсов во время выполнения.
Включите действие: например, <jsp: include page = "copyright.jsp" />. Это действие представляет результат, сгенерированный после выполнения указанной страницы. Поскольку он завершается во время выполнения, управление выходными результатами является более гибким. Тем не менее, это экономически эффективно использовать действие, включите действие, когда котируемый контент часто изменяется, или когда ссылочная страница не может быть определена до того, как появится запрос на главную страницу.
24. Ясно, что больше не нужны сессии во времени
Чтобы очистить сеансы, которые больше не активны, многие серверы приложений имеют тайм -аут сеанса по умолчанию, обычно 30 минут. Когда сервер приложений должен сохранять больше сеансов, если емкость памяти недостаточно, операционная система будет передавать часть данных памяти на диск. Хранить на диск и даже выбросить исключение «вне памяти». В крупномасштабных системах сеансы сериализации стоят дорого. Когда сеанс больше не требуется, метод httpsessession.invalidate () должен быть вызван во времени, чтобы очистить сеанс. Метод httpsessession.invalidate () обычно может быть вызван на странице выхода приложения.
25. Не объявляйте массив как: публичный статический финал.
26. Обсуждение по эффективности обходов HashMap
Часто существуют операции по переселению в парах ключей и значений в Hashmap, и есть два метода: map <string, string []> paramap = new
Hashmap <String, String []> (); ............ // Первый цикл SET <String> appfieldDefids = paramap.keyset (); ] values = paramap.get (appfieldDefid); ......} // второй цикл для (entry <string, string []> intpirt: paramap.EntrySet ()) {string appfieldDefid = entry.getKey ( ); String [] values = intry.getValue (); .......} Первая реализация значительно менее эффективна, чем вторая реализация.
Анализ выглядит следующим образом, set <string> appfielddefids = paramap.keyset ();
Код заключается в следующем:
public set <k> keyset () {set <k> ks = keyset; return (ks! = null? ks: (keyset = new Keyset ()));} Keyset Private Class Extends AbstractSet <k> {public iterator <k > iterator () {return newKeyiterator ();} public int size () {return size;} public boolean содержит (Object o) {return containsKey (o);} public boolean remove (Object o) {return hashmap.This.RemoveEntryForkey (o)! = null;} public void clear () {hashmap.this.clear ();}}Фактически, он возвращает личный класс класса, который унаследован от AbstractSet и реализует интерфейс SET.
Давайте посмотрим на синтаксис для/в петлях
для (объявление: выражение)
заявление
На этапе выполнения он переводится в следующие формулы
for (iterator <e> #i = (Expression) .iterator (); #i.hashnext ();) {
Declaration = #i.next ();
заявление
}
Следовательно, hashmap.keyset (). Iterator () вызывается в первом для оператора для (String AppfieldDefid: AppfieldDefids)
Этот метод вызывает newKeyiterator ()
Iterator <k> newkeyiterator () {
вернуть новый KeyTerator ();
}
Частный класс KeyTerator расширяет Hashiterator <k> {
public k next () {
return nextentry (). getKey ();
}
}
Таким образом, в FO, итератор, используемый во втором цикле для (entry <string, string []> intpirt: paramap.EntrySet ()), называется следующим образом.
добрый
Частный класс entryTerator Extends hashiterator <map.entry <K, v >> {
public Map.Entry <K, v> next () {
return nextentry ();
}
}
В настоящее время первый цикл получает ключ, а второй цикл получает эффективность ввода Hashmap заключается в том, что второй цикл отражается в цикле. Используйте HashMap's Get (объектный ключ), чтобы получить значение значения теперь посмотрите на метод HashMap's get (ключ объекта)
public v get (object key) {
Объект k = masknull (ключ);
int hash = hash (k);
int i = indexfor (hash, table.length);
Вход <K, V> e = таблица;
while (true) {
if (e == null)
вернуть ноль;
if (e.hash == hash && eq (k, e.key)))
вернуть E.value;
e = e.next;
}
}
Фактически, он должен использовать значение хэша, чтобы снова получить соответствующую запись, чтобы сравнить и получить результат.
Во втором цикле получает входное значение, а затем непосредственно берет ключ и значение, что более эффективно, чем первый цикл. На самом деле, согласно концепции карты, должно быть лучше использовать второй цикл.
27. Использование массива (массив) и Arrylist
Массив ([]): наиболее эффективно;
Arraylist: емкость может расти динамически;
Основываясь на эффективности и проверке типа, массив должен использоваться как можно больше.
ArrayList - сложная версия массива
ArrayList инкапсулирует массив типа объекта Метод массива.
Когда ArrayList хранит объект, информация о типе отбрасывается, и все объекты блокируются как объект.
ПРИМЕЧАНИЕ. JDK5 добавила поддержку Generics, и проверка типов может быть выполнена при использовании ArrayList.
С этой точки зрения, разница между ArrayList и Array в основном связана с эффективностью динамического увеличения емкости.
28. Попробуйте использовать Hashmap и Arraylist .
29. Разница между StringBuffer и StringBuilder:
java.lang.stringbuffer Thread-Safe Mintable символа. Строковый буфер строк, но не может быть изменен.
StringBuilder. По сравнению с этим классом, класс Java.lang.stringBuilder обычно должен быть предпочтительным, поскольку он поддерживает все одинаковые операции, но он быстрее, потому что он не выполняет синхронизацию. Для лучшей производительности, способность Stirngbuffer или Stirngbuilder должна быть указана как можно больше. Конечно, если строка, которой вы работаете, не превышает 16 символов, вам не понадобится. В том же случае, используя Fryngbuilder может достичь только примерно на 10-15% повышения производительности по сравнению с использованием StringBuffer, но он рискует небезопасным. В реальном модульном программировании программист, ответственный за определенный модуль, может быть не в состоянии четко определить, будет ли модуль будет помещен в многопоточную среду, поэтому, если вы не можете определить, что узкая часть вашей системы находится на StringBuffer, и и и Убедитесь, что ваш модуль не будет работать в многопоточном режиме, в противном случае используйте StringBuffer.
Другие добавки:
1. Чистые объекты, которые больше не используются во времени и устанавливаются на NULL
2. Используйте окончательные, статические и другие ключевые слова как можно больше
3. Используйте заземленные объекты как можно больше
Как оптимизировать код для создания исходного файла Java и скомпилированного файла класса меньше
1 Попробуйте использовать наследство.
2 Откройте параметры оптимизации компилятора Java: javac -o Эта опция удалит номер строки в файле класса и объявляет некоторые частные, статические и конечные методы малого сегмента в качестве встроенных вызовов метода
3 Извлеките общий код
4 Не инициализируйте большие массивы. Хранится в массиве, вы можете сначала поместить эти данные в строку, а затем разобрать строку в массив во время выполнения
5. Объекты типа даты займет много места.
длинный тип, затем преобразуйте в тип даты при использовании при использовании
6. Попробуйте использовать короткие имена для имен классов, имен методов и имен переменных.
7 Определите переменные статического конечного типа в интерфейс
8 Если арифметические операции могут использоваться для левого / правого движения, не используйте * и / операции.
2. Не инициализируйте переменные дважды
Java инициализирует переменную для известного значения по умолчанию, вызывая уникальный конструктор класса. Все объекты установлены на NULL, целые числа (байт, короткие, Int, Long) устанавливаются на 0, Float и Double установлены на 0,0, а логические переменные устанавливаются на FALSE. Это особенно важно для классов, которые простираются от других классов, как и все серии конструкторов, автоматически называемые при создании объекта с использованием нового ключевого слова.
3. Сделайте класс окончательным, где это возможно
Занятые финалы не могут быть расширены. В основном API есть много примеров этой технологии, таких как Java.Lang.String. Маркировка класса строки как окончательный не позволяет разработчикам создавать методы длины, которые они реализуют сами.
Чтобы выразить это глубже, если класс является окончательным, все методы класса являются окончательными. Компилятор Java может внедрить все методы (это зависит от реализации компилятора). В моих тестах я видел среднее повышение производительности на 50%.
9. Исключение брошено на то, что его нужно бросить.
try {some.method1 (); (Method2exception e) {// Обработка исключения 2} try {ask.method3 (); Код, который был загружен, легче оптимизировать компилятором
Попробуйте {some.method1 (); Catch (Method3exception e) {// Обработка исключения 3}
10. Оптимизация для петли
Заменять…
for (int i = 0; i <collection.size (); i ++) {
...
}
с…
for (int i = 0, n = collection.size (); i <n; i ++) {
...
}
5. При разработке системы приложений Java + Oracle попробуйте использовать встроенные заявления SQL -заявления в верхней регистрации в Java, чтобы уменьшить бремя разбора синтаксического анализатора Oracle.
10. Попробуйте принять ленивую стратегию загрузки, то есть начать создавать при необходимости.
Например: string str = «aaa»;
if (i == 1) {
list.add (str);
}
Следует заменить на:
if (i == 1) {
String str = «aaa»;
list.add (str);
}
12. Не используйте его в цикле:
Пытаться {
} ловить() {
}
Он должен быть помещен на самый внешний слой
Выше всего об этой статье.
Пожалуйста, найдите время, чтобы поделиться статьей со своими друзьями или оставить комментарий. Мы искренне благодарим вас за вашу поддержку!