IT 강좌(IT Lectures)/Java

11강. Java 성능 최적화

소울입니다 2024. 6. 28. 08:30
728x90
반응형

챕터 11: Java 성능 최적화


Java 애플리케이션의 성능을 최적화하는 것은 중요한 과제입니다. 이 장에서는 JVM 튜닝, 메모리 관리 및 가비지 컬렉션, 그리고 성능 분석 도구 사용법을 다룹니다. 다양한 예제와 코드를 통해 성능 최적화 방법을 상세히 설명합니다.

11.1 JVM 튜닝

JVM의 구조와 동작 원리를 이해하고, 힙 메모리 관리와 가비지 컬렉션 튜닝을 통해 성능을 최적화할 수 있습니다.

 

11.1.1 JVM의 구조와 동작 원리

JVM(Java Virtual Machine)은 Java 프로그램을 실행하는 가상 머신입니다. JVM의 주요 구성 요소는 다음과 같습니다:

  • 클래스 로더(Class Loader): 클래스 파일을 로드합니다.
  • 메모리 영역(Memory Area): 메소드 영역, 힙, 스택, PC 레지스터, 네이티브 메소드 스택으로 구성됩니다.
  • 실행 엔진(Execution Engine): 바이트코드를 실행합니다.
  • 네이티브 메서드 인터페이스(Native Method Interface): 네이티브 메서드를 호출할 수 있게 합니다.

11.1.2 힙 메모리 관리와 가비지 컬렉션 튜닝

힙 메모리는 객체를 저장하는 공간입니다. JVM은 자동으로 가비지 컬렉션을 수행하여 더 이상 사용되지 않는 객체를 제거합니다. 힙 메모리를 효율적으로 관리하고 가비지 컬렉션을 튜닝하면 성능을 향상시킬 수 있습니다.

 

예제: JVM 옵션 설정

java -Xms512m -Xmx1024m -XX:+UseG1GC -jar myapp.jar
 

설명:

  • -Xms: 초기 힙 메모리 크기를 설정합니다.
  • -Xmx: 최대 힙 메모리 크기를 설정합니다.
  • -XX:+UseG1GC: G1 가비지 컬렉터를 사용하도록 설정합니다.

힙 메모리 튜닝 예제

public class MemoryExample {
    public static void main(String[] args) {
        // 큰 배열 할당
        int[] largeArray = new int[1000000];
        
        // JVM 메모리 정보 출력
        Runtime runtime = Runtime.getRuntime();
        System.out.println("Total Memory: " + runtime.totalMemory());
        System.out.println("Free Memory: " + runtime.freeMemory());
        
        // 큰 배열 제거
        largeArray = null;
        
        // 가비지 컬렉션 강제 실행
        System.gc();
        
        System.out.println("Free Memory after GC: " + runtime.freeMemory());
    }
}
 

설명:

  • Runtime.getRuntime(): 현재 JVM의 런타임 객체를 반환합니다.
  • totalMemory(): JVM이 현재 사용 중인 메모리 양을 반환합니다.
  • freeMemory(): JVM이 사용할 수 있는 여유 메모리 양을 반환합니다.
  • System.gc(): 가비지 컬렉션을 강제로 실행합니다.

11.2 메모리 관리와 가비지 컬렉션

메모리 관리는 Java 애플리케이션의 성능 최적화에 중요한 요소입니다.

 

11.2.1 메모리 누수와 그 예방 방법

메모리 누수는 더 이상 필요하지 않은 객체가 메모리에서 해제되지 않고 계속해서 유지되는 상황을 의미합니다. 이를 예방하려면 다음과 같은 방법을 사용할 수 있습니다:

  • 객체 참조 해제: 더 이상 사용하지 않는 객체의 참조를 해제합니다.
  • 캐시 관리: 캐시를 사용 중이라면, 주기적으로 불필요한 객체를 제거합니다.
  • Weak References: 메모리 누수를 방지하기 위해 Weak Reference를 사용할 수 있습니다.

예제: 메모리 누수 방지

import java.util.ArrayList;
import java.util.List;

public class MemoryLeakExample {
    private List<Object> cache = new ArrayList<>();

    public void addToCache(Object obj) {
        cache.add(obj);
    }

    public void clearCache() {
        cache.clear();
    }

    public static void main(String[] args) {
        MemoryLeakExample example = new MemoryLeakExample();
        for (int i = 0; i < 10000; i++) {
            example.addToCache(new Object());
        }
        System.out.println("Cache size before clear: " + example.cache.size());
        example.clearCache();
        System.out.println("Cache size after clear: " + example.cache.size());
    }
}
 

설명:

  • cache.clear(): 캐시를 비워 메모리 누수를 방지합니다.

11.2.2 다양한 가비지 컬렉션 알고리즘

JVM은 다양한 가비지 컬렉션 알고리즘을 제공합니다. 각 알고리즘은 특정 상황에서 더 효율적일 수 있습니다.

주요 가비지 컬렉션 알고리즘:

  • Serial GC: 단일 스레드로 가비지 컬렉션을 수행합니다.
  • Parallel GC: 여러 스레드를 사용하여 가비지 컬렉션을 병렬로 수행합니다.
  • CMS (Concurrent Mark-Sweep) GC: 애플리케이션의 중단 시간을 최소화합니다.
  • G1 (Garbage-First) GC: 대용량 힙에서 성능을 최적화합니다.

예제: 다양한 GC 알고리즘 사용

# Serial GC 사용
java -XX:+UseSerialGC -jar myapp.jar

# Parallel GC 사용
java -XX:+UseParallelGC -jar myapp.jar

# CMS GC 사용
java -XX:+UseConcMarkSweepGC -jar myapp.jar

# G1 GC 사용
java -XX:+UseG1GC -jar myapp.jar
 

11.3 성능 분석 도구 사용법

성능 분석 도구를 사용하여 애플리케이션의 성능 병목 지점을 파악하고 해결할 수 있습니다.

 

11.3.1 JVisualVM 사용법

JVisualVM은 JVM 모니터링, 성능 분석 및 디버깅 도구입니다.

 

JVisualVM 설치 및 실행

  1. JDK와 함께 설치된 JVisualVM을 실행합니다.
  2. 애플리케이션의 JVM을 선택합니다.
  3. 모니터, 스레드, 메모리, CPU 사용량 등을 실시간으로 모니터링합니다.

예제: JVisualVM 사용

public class CPUBoundExample {
    public static void main(String[] args) {
        long sum = 0;
        for (long i = 0; i < 1_000_000_000L; i++) {
            sum += i;
        }
        System.out.println("Sum: " + sum);
    }
}
 

설명:

  • JVisualVM을 사용하여 CPU 사용량을 모니터링하고, CPU가 많이 사용되는 코드를 식별할 수 있습니다.

11.3.2 JProfiler 사용법

JProfiler는 강력한 Java 프로파일링 도구로, 애플리케이션의 성능 병목 지점을 파악하고 해결하는 데 도움을 줍니다.

 

JProfiler 설치 및 설정

  1. JProfiler 웹사이트에서 JProfiler를 다운로드하고 설치합니다.
  2. JProfiler를 실행하고 애플리케이션의 JVM을 선택합니다.
  3. CPU, 메모리, 스레드 사용량 등을 분석합니다.

예제: JProfiler 사용

import java.util.ArrayList;
import java.util.List;

public class MemoryBoundExample {
    public static void main(String[] args) {
        List<byte[]> memoryConsumers = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            memoryConsumers.add(new byte[1_000_000]); // 메모리 할당
        }
        System.out.println("Memory allocated");
    }
}
 

설명:

  • JProfiler를 사용하여 메모리 사용량을 모니터링하고, 메모리 누수가 발생하는 지점을 식별할 수 있습니다.

추가 예제: JVisualVM을 사용한 힙 덤프 분석

public class HeapDumpExample {
    public static void main(String[] args) {
        List<byte[]> memoryConsumers = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            memoryConsumers.add(new byte[10_000_000]); // 메모리 할당
        }

        // 힙 덤프 생성
        System.out.println("Heap dump created");
        // JVisualVM에서 힙 덤프를 분석하여 메모리 사용량을 확인할 수 있습니다.
    }
}
 

설명:

  • 힙 덤프(Heap Dump): JVM 힙 메모리의 스냅샷을 생성하여 메모리 사용량을 분석합니다. JVisualVM을 사용하여 힙 덤프를 생성하고 분석할 수 있습니다.

추가 예제: JProfiler를 사용한 CPU 프로파일링

public class CpuProfilingExample {
    public static void main(String[] args) {
        long startTime = System.nanoTime();

        // CPU 집약적인 작업
        long sum = 0;
        for (long i = 0; i < 1_000_000_000L; i++) {
            sum += i;
        }

        long endTime = System.nanoTime();
        System.out.println("Sum: " + sum);
        System.out.println("Execution Time: " + (endTime - startTime) / 1_000_000 + " ms");
    }
}
 

설명:

  • CPU 프로파일링: JProfiler를 사용하여 CPU 사용량을 모니터링하고, CPU 집약적인 작업이 실행되는 시간을 측정할 수 있습니다.

이로써 Java 성능 최적화에 대해 자세히 설명하고, 각 개념을 코드와 예시를 통해 설명했습니다. 이를 통해 JVM 튜닝, 메모리 관리 및 가비지 컬렉션, 성능 분석 도구 사용법 등을 이해하고 활용할 수 있게 됩니다. 다음 챕터에서는 Java의 보안과 암호화에 대해 다루겠습니다.

반응형

'IT 강좌(IT Lectures) > Java' 카테고리의 다른 글

13강. Spring 프레임워크  (0) 2024.06.30
12강. 보안과 암호화  (0) 2024.06.29
10강. 기초 프로젝트  (0) 2024.06.27
9강. 파일 I/O 및 네트워킹  (0) 2024.06.26
8강. 스트림과 컬렉션 프레임워크  (0) 2024.06.25