대부분의 개발자들은 성능 최적화가 비교적 복잡한 문제이며 많은 경험과 지식이 필요하다고 생각합니다. 예, 그것에 아무런 문제가 없습니다. 물론 최고의 성능을 위해 응용 프로그램을 최적화하는 것은 쉬운 일이 아니지만,이 경험과 지식을 얻지 않고는 아무것도 할 수 없다는 것을 의미하지는 않습니다. 다음은 잘 수행하기 쉬운 팁과 모범 사례가 잘 실적이 좋은 응용 프로그램을 만드는 데 도움이 될 수 있습니다.
이러한 제안의 대부분은 Java 기반이지만 반드시 필요한 것은 아니며 일부는 모든 응용 프로그램 및 프로그래밍 언어에 적용될 수 있습니다. Java 기반 성능 튜닝 팁을 공유하기 전에 이러한 일반적인 성능 튜닝 팁에 대해 논의 해 봅시다.
1. 필요하기 전에 최적화하지 마십시오
이것은 아마도 가장 중요한 성능 튜닝 팁 중 하나 일 것입니다. 일반적인 모범 사례를 따르고 사용 사례를 효과적으로 구현해야합니다. 그러나 이것이 필요하다는 것을 증명하기 전에 표준 라이브러리를 대체하거나 복잡한 최적화를 구축하는 것은 아닙니다.
대부분의 경우 조기 최적화는 많은 시간이 걸리므로 코드를 읽고 유지하기가 어렵습니다. 더 나쁜 것은, 이러한 최적화는 일반적으로 애플리케이션의 비정규 적 부분을 최적화하는 데 많은 시간을 소비하기 때문에 어떤 이점이 없습니다.
그렇다면 무언가를 최적화해야한다는 것을 어떻게 증명합니까?
먼저, 모든 API 호출에 대한 최대 응답 시간을 지정하거나 특정 시간 범위에서 가져올 레코드 수를 지정하는 것과 같이 응용 프로그램 코드의 속도를 결정해야합니다. 완료되면 응용 프로그램의 어느 부분이 너무 느리게 개선하기에는 측정 할 수 있습니다. 이 작업을 수행 한 후 두 번째 튜닝 팁을 계속보십시오.
2. 분석기를 사용하여 실제 병목 현상을 찾으십시오
첫 번째 조언을 따르고 응용 프로그램의 일부 부분이 개선이 필요하다고 판단한 후에는 어디서부터 시작 해야할지 스스로에게 문의 하시겠습니까?
이 문제를 두 가지 방법으로 해결할 수 있습니다.
두 번째 방법을 항상 따라야하는 이유는 무엇입니까?
답은 분명해야하며 분석기 기반 접근 방식을 사용하면 코드의 성능을 더 잘 이해하고 가장 중요한 부분에 집중할 수 있습니다. 파서를 사용한 적이 있다면 코드의 부분이 성능 문제를 일으키는 것에 놀랄 것입니다. 그러나 여러 번, 첫 번째 추측은 당신을 잘못된 방향으로 이끌 것입니다.
3. 전체 애플리케이션에 대한 성능 테스트 스위트 생성
이는 성능 개선이 생산 환경에 배치 된 후 종종 발생하는 예상치 못한 많은 문제를 피하는 데 도움이되는 또 다른 일반적인 트릭입니다. 종종 전체 응용 프로그램을 테스트하고 성능 향상을 완료하기 전후에 실행하는 성능 테스트 제품군을 정의해야합니다.
이러한 추가 테스트 실행은 변경의 기능적 및 성능 영향을 식별하고 좋은 것보다 더 해로운 업데이트를 해제하지 않도록하는 데 도움이됩니다. 작업이 데이터베이스 또는 캐시와 같은 응용 프로그램의 여러 다른 부분에서 실행되는 경우 특히 중요합니다.
4. 먼저 가장 큰 병목 현상 문제를 해결하십시오
테스트 스위트를 작성하고 분석기를 사용하여 응용 프로그램을 분석 한 후에는 성능을 향상시키는 데 필요한 질문 목록이 있지만, 이는 여전히 시작 해야하는 질문에 답하지 않습니다. 빠르게 수행 할 수있는 것부터 시작하거나 가장 중요한 질문으로 시작할 수 있습니다.
물론 전자는 곧 결과를 얻을 것이기 때문에 매우 유혹적입니다. 때로는 다른 팀원이나 경영진이 성능 분석이 그만한 가치가 있다고 확신해야 할 수도 있습니다.
그러나 전반적으로 가장 중요한 성능 문제로 시작하는 것이 좋습니다. 이렇게하면 성능이 가장 큰 개선이 가능하며 성능 요구를 해결하기 위해 이러한 문제 중 몇 가지만 해결하면됩니다.
일반적인 성능 튜닝 기술을 이해 한 후에는 Java 특정 튜닝 기술을 자세히 살펴 보겠습니다.
5. StringBuilder를 사용하여 프로그래밍 방식으로 문자열을 연결하십시오
Java에는 문자열을 연결하기위한 다양한 옵션이 있습니다. 예를 들어, 간단한 + 또는 + =, 오래된 StringBuffer 또는 StringBuilder를 사용할 수 있습니다.
그렇다면 어떤 방법을 선택해야합니까?
답은 문자열을 연결하는 코드에 따라 다릅니다. 예를 들어 For Loop에서 문자열에 새 컨텐츠를 프로그래밍 방식으로 추가하는 경우 StringBuilder를 사용해야합니다. 사용하기 쉽고 StringBuffer보다 더 나은 성능을 제공합니다. 그러나 StringBuilder는 StringBuffer와 다르며 스레드 안전이 아니며 모든 사용 사례에 적합하지 않을 수 있습니다.
새 StringBuilder를 인스턴스화하고 Append 메소드를 호출하여 문자열에 새 부분을 추가하면됩니다. 모든 부품을 추가 한 후에는 toString () 메소드를 호출하여 연결 문자열을 검색 할 수 있습니다.
다음 코드 스 니펫은 간단한 예를 보여줍니다. 각 반복하는 동안이 루프는 I를 문자열로 변환하여 StringBuilder SB의 공간으로 추가 하므로이 코드는 "this is is test0123456789"에 로그 파일에 기록됩니다.
StringBuilder sb = new StringBuilder ( "이것은 테스트입니다"); for (int i = 0; i <10; i ++) {sb.append (i); sb.append ( "");} log.info (sb.tostring ());코드 스 니펫에서 볼 수 있듯이 생성자 메소드에 대한 문자열의 첫 번째 요소를 제공 할 수 있습니다. 이렇게하면 제공된 문자열과 16 개의 추가 문자 용량이있는 새 StringBuilder가 생성됩니다. StringBuilder에 더 많은 문자를 추가하면 JVM은 StringBuilder의 크기를 동적으로 변경합니다.
문자열에 포함 된 문자 수를 이미 알고 있다면이 숫자를 다른 생성자 메소드에 제공하여 정의 된 용량으로 StringBuilder를 인스턴스화 할 수 있습니다. 이는 용량을 동적으로 확장 할 필요가 없기 때문에 효율성을 향상시킵니다.
6. 선언에서 +연결 문자열을 사용합니다
Java에서 첫 번째 애플리케이션을 구현할 때 누군가는 문자열을 연결하는 데 +를 사용해서는 안된다고 말할 수 있습니다. 응용 프로그램 로직에서 문자열을 연결하는 경우에 맞습니다. 문자열은 불변이며 각 문자열의 결과는 새로운 문자열 객체에 저장됩니다. 이를 위해서는 여분의 메모리가 필요하고 특히 루프에서 여러 문자열을 연결할 때 응용 프로그램을 속도로 느리게합니다.
이 경우 팁 5를 따라 StringBuilder를 사용해야합니다.
그러나 코드의 가독성을 향상시키기 위해 문자열을 여러 줄로 나누면 그렇지 않습니다.
query q = em.createquery ( "select a.id, a.firstname, a.lastname"+ "a aworge a"+ "여기서 a.id = : id");
이 경우 간단한 +를 사용하여 문자열을 연결해야합니다. Java 컴파일러는이를 최적화하고 컴파일 시간에 연결을 수행합니다. 따라서 런타임에 코드는 1 문자 만 사용하며 연결이 필요하지 않습니다.
7. 기본 데이터 유형을 가능한 한 많이 사용하십시오
오버 헤드를 피하고 응용 프로그램 성능을 향상시키는 또 다른 빠른 방법은 래퍼 클래스 대신 원시 데이터 유형을 사용하는 것입니다. 따라서 정수 대신 int를 사용하거나 이중 대신 더블을 사용하는 것이 좋습니다. 따라서 JVM은 스택에 값을 저장하여 메모리 소비를 줄이고보다 효율적으로 처리 할 수 있습니다.
8. Biginteger와 Bigdecimal을 피하십시오
우리는 데이터 유형에 대해 논의 했으므로 BigInteger와 Bigdecimal을 살펴 보겠습니다. 후자는 특히 정밀도로 인해 인기가 있습니다. 그러나 가격이 있습니다.
Biginteger와 Bigdecimal은 단순한 길거나 두 배보다 더 많은 메모리가 필요하며 모든 계산 속도를 크게 줄입니다. 따라서 여분의 정밀도가 필요하거나 숫자가 장거리를 넘어서면 두 번 생각하기 전에 두 번 생각하는 것이 가장 좋습니다. 이곳은 특히 수학 알고리즘을 구현할 때 성능 향상 문제를 변경 해야하는 유일한 장소 일 것입니다.
9. 먼저 현재 로그 레벨을 확인하십시오
이 제안은 분명하지만 불행히도 많은 코드가 무시한다는 것을 알게 될 것입니다. 디버그 메시지를 만들기 전에 먼저 현재 로그 레벨을 확인해야합니다.
다음은이 작업을 수행해서는 안된다는 것을 설명하기위한 두 가지 예입니다.
// thislog.debug ( "user [" + username + "]는 [" + i + "]" "); // thislog.debug (String.format ("user [%s] with [%d] ", username, i);두 경우 모두 로그 프레임 워크가 로그 메시지를 사용하는지 여부를 알지 못하고 로그 메시지를 작성하는 데 필요한 모든 단계를 수행합니다. 디버그 메시지를 작성하기 전에 먼저 현재 로그 레벨을 확인하는 것이 가장 좋습니다.
10. Apache Commons StringUtils.replace를 사용하여 String.replace를 사용하십시오
일반적으로 String.replace 메소드는 잘 작동하고 특히 Java 9를 사용하는 경우 매우 효율적입니다. 그러나 응용 프로그램에 많은 교체 작업이 필요하고 최신 Java 버전으로 업데이트되지 않은 경우 더 빠르고 효율적인 대안을 확인하는 것이 좋습니다.
한 후보자는 Apache Commons Lang의 StringUtils.replace 방법입니다. Lukas Eder가 최근 블로그 게시물에서 설명했듯이 Java 8의 String.replace 메소드보다 크게 중요합니다.
작은 변화 만 있으면됩니다. Apache의 Commons Lang 프로젝트에 대한 App Pom.xml에 Maven 의존성을 추가하고 모든 통화를 String.replace Methods를 StringUtils.replace Methods로 교체하면됩니다.
// thistest.replace ( "테스트", "간단한 테스트"); // thisstringUtils.replace (테스트, "테스트", "간단한 테스트")를 대체합니다.
11. 데이터베이스 연결과 같은 비싼 리소스를 캐시합니다
캐싱은 비싸거나 자주 사용하는 코드 스 니펫의 반복적 인 실행을 피하기위한 인기있는 솔루션입니다. 일반적인 아이디어는 간단합니다. 새로운 리소스를 반복해서 만드는 것보다 이러한 리소스를 재사용하는 것이 훨씬 저렴합니다.
일반적인 예는 풀의 캐시 데이터베이스 연결입니다. 새 연결을 만드는 데 시간이 걸리고 기존 연결이 재사용되면 피할 수 있습니다.
다른 예는 Java 언어 자체에서도 찾을 수 있습니다. 예를 들어, 정수 클래스의 가치는 -128에서 127 사이의 값을 캐시합니다. 새 정수를 만드는 것이 너무 비싸지 않지만 종종 사용되며 가장 일반적으로 사용되는 값을 캐싱하면 성능 이점을 제공한다고 말할 수 있습니다.
그러나 캐싱에 대해 생각할 때 캐시 구현도 오버 헤드가 발생할 수 있습니다. 재사용 가능한 리소스를 저장하려면 추가 메모리를 사용해야하므로 리소스가 구식 리소스에 액세스하거나 삭제할 수 있도록 캐시를 관리해야 할 수도 있습니다.
따라서 자원을 캐싱하기 전에 자주 리소스를 사용하십시오.
요약
보시다시피 응용 프로그램의 성능을 향상시키는 경우 가끔 많은 작업이 필요하지 않습니다. 이 기사의 대부분의 제안은 실제로 코드에 적용하기 위해 약간의 노력이 필요합니다.
그러나 가장 중요한 조언은 언어 독립적 인 매우 프로그래밍된다는 것입니다.
원본 링크 : 11 간단한 Java 성능 튜닝 팁 (편집기/Wei Wei)