>  기사  >  Java  >  JVM 잠금 최적화 이해

JVM 잠금 최적화 이해

DDD
DDD원래의
2024-09-23 16:16:39362검색

Understanding JVM Lock Optimizations

여러 동시 작업을 수행할 수 있는 강력하고 확장 가능한 애플리케이션을 개발하려면 동시성이 매우 중요합니다. 그러나 이를 위해서는 동기화 측면에서 대가를 지불해야 합니다. 잠금 획득 및 해제에 수반되는 오버헤드로 인해 성능 비용이 발생합니다. 이러한 성능 비용을 줄이기 위해 편향된 잠금, 잠금 제거, 잠금 거칠기화, 경량 및 중량 잠금 개념 등 여러 가지 최적화 기능이 JVM에 통합되었습니다.

이 기사에서는 이러한 최적화에 대해 더 자세히 살펴보고 멀티 스레드 Java 애플리케이션에서 동기화를 향상시키는 방법을 살펴봅니다.

Java 잠금 기본 사항

Java에서는 블록이나 메소드의 동기화를 통해 한 번에 하나의 스레드만 코드의 중요한 섹션을 실행할 수 있습니다. 이는 다중 스레드 환경 내에서 리소스 공유를 고려할 때 특히 중요합니다. Java는 내장 잠금을 사용하여 이를 구현합니다. 때로는 동기화된 블록을 사용하여 스레드에 대한 액세스를 관리하는 데 도움이 되는 개체 또는 클래스와 연결된 모니터라고도 합니다.

스레드 안전성을 위해서는 동기화가 필수이지만 경합이 낮거나 전혀 없을 경우 비용이 상당히 많이 들 수 있습니다. JVM 최적화가 프레임에 들어가는 곳입니다. 따라서 잠금 비용이 절감되고 전반적인 성능이 향상됩니다.

1. 편향된 잠금

편향 잠금이란 무엇인가요?

편향된 잠금은 잠금 획득 오버헤드를 줄이는 것을 목표로 하는 최적화입니다. 이는 단일 스레드에 의해 지배되거나 단일 스레드에 의해 가장 많이 액세스되는 잠금 획득 비용을 줄이기 위해 최적화되었습니다. 이러한 프로그램은 종종 다른 스레드와의 경합 없이 동일한 스레드에 의해 잠금을 획득하고 해제합니다. JVM은 이 패턴을 인식하고 해당 특정 스레드에 대한 잠금을 바이어스할 수 있습니다. 다음 잠금 획득은 거의 무료입니다.

편향 잠금은 어떻게 작동하나요?

편향 잠금이 활성화되면 스레드가 처음으로 잠금을 획득할 때 잠금이 해당 스레드 쪽으로 편향되게 됩니다. 스레드의 ID는 잠금 개체의 헤더에 기록되며 해당 스레드에 의한 후속 잠금 획득에는 동기화가 전혀 포함되지 않습니다. 잠금이 현재 스레드 쪽으로 편향되어 있는지 확인하기만 하면 됩니다. 이는 매우 빠르고 비차단 작업입니다. .

다른 스레드가 잠금을 획득하려고 하면 바이어스가 취소되고 JVM은 바이어스되지 않은 표준 잠금 메커니즘으로 돌아갑니다. 이 단계에서는 이제 표준 잠금이 되며 두 번째 스레드는 표준 잠금 프로세스를 통해 이를 획득해야 합니다.
편향 잠금의 이점

성능: 바이어스 잠금에서 동일한 스레드 획득은 거의 무료 잠금 획득입니다.

따라서 다른 스레드가 잠금 획득에 참여할 기회가 없으므로 경합 처리가 필요하지 않습니다.

낮은 오버헤드: 경합이 발생하는 경우를 제외하고는 잠금 상태를 변경하거나 동기화 관련 메타데이터를 수정할 필요가 없습니다. 
 

편향 잠금은 언제 사용되나요?

편향된 잠금은 단일 스레드 애플리케이션이나 다중 스레딩에서 잠금 경합이 낮은 애플리케이션과 같이 주로 동일한 스레드에서 잠금에 액세스하는 애플리케이션에 유용합니다. 대부분의 JVM에서는 기본적으로 활성화되어 있습니다.

편향 잠금 비활성화 방법

편향 잠금은 기본적으로 활성화되어 있지만 아래와 같이 JVM 플래그를 사용하여 비활성화할 수도 있습니다.

-XX:-BiasedLocking 사용

2. 잠금 제거

잠금 제거란 무엇인가요?

잠금 제거는 JVM이 일부 불필요한 동기화(잠금)를 완전히 제거하는 매우 강력한 최적화입니다. JIT 컴파일 중에 코드를 검사하여 동기화가 필요하지 않음을 확인합니다. 이는 일반적으로 하나의 스레드에서만 잠금에 액세스했거나 JVM을 사용하여 동기화하는 개체가 다른 스레드 내에서 동일한 개체를 공유하지 않는 경우에 발생합니다. JVM이 더 이상 필요하지 않다고 판단하면 잠금이 제거됩니다.

잠금 제거는 어떻게 작동하나요?

JIT 컴파일의 이스케이프 분석 단계에서 JVM은 객체가 단일 스레드에 국한되어 있는지 아니면 로컬 컨텍스트에서만 사용되는지 확인합니다. 개체가 자신을 생성한 스레드의 범위를 벗어나지 않기 때문에 해당 개체에 대한 동기화를 제거할 수 있다면 그렇게 됩니다.

예를 들어, 객체가 메소드 내에서 완전히 생성되고 사용되는 경우(스레드 간에 공유되지 않음) JVM은 다른 스레드가 해당 객체에 액세스할 수 없다는 것을 인식하므로 모든 동기화가 중복됩니다. 이러한 경우 JIT 컴파일러는 단순히 잠금을 완전히 제거합니다.

잠금 오버헤드 제로: 불필요한 동기화를 제거하면 JVM이 애초에 잠금을 획득하고 해제하는 데 드는 비용을 지불하지 않아도 됩니다.

더 높은 처리량: 특히 코드에 동기화된 블록이 많이 포함된 경우 데드 동기화로 인해 애플리케이션의 처리량이 더 높아질 수 있습니다.

이 코드를 살펴보세요.

public void someMethod() {
    StringBuilder sb = new StringBuilder();
    synchronized (sb) {
        sb.append("Hello");
        sb.append("World");
    }
}

이 경우 StringBuildersomeMethod 내에서만 사용되고 다른 스레드 간에 공유되지 않으므로 sb에 대한 동기화는 필요하지 않습니다. 이를 살펴보면 JVM은 이스케이프 분석을 수행하여 잠금을 제거할 수 있습니다.

3. 잠금 강화

Lock Coarsening이란 무엇인가요?

잠금 조대화는 루프나 작은 코드 섹션에서 잠금을 지속적으로 획득하고 해제하는 대신 JVM이 잠금 범위를 확장하여 더 많은 코드 덩어리를 포함하는 최적화입니다.

락 조대화 작업

JVM이 긴밀한 루프 또는 인접한 여러 코드 블록이 잠금을 너무 자주 획득하고 해제하는 것을 발견하면 루프 외부 또는 여러 코드 블록에 걸쳐 잠금을 수행하여 잠금을 거칠게 할 수 있습니다. 이로 인해 무잠금 획득 및 해제 비용이 많이 들고 스레드가 더 많은 반복을 위해 잠금을 보유할 수 있습니다.

코드 예: 잠금 강화

다음 코드 조각을 고려하세요.

for (int i = 0; i < 1000; i++) {
    synchronized (lock) {
        // Do something
    }
}

잠금 조대화는 잠금 획득을 루프 외부로 푸시하므로 스레드는 한 번만 잠금을 획득합니다.

synchronized (lock) {
  for (int i = 0; i < 1000; i++) {
    // Do something
  }
}

JVM은 추가 잠금 획득 및 해제를 방지하여 성능을 획기적으로 향상시킬 수 있습니다.

잠금 강화 혜택

잠금 오버헤드의 자유도 감소: 축소는 특히 수천 번 반복된 루프와 같은 핫스팟 코드에서 잠금 획득 및 해제를 방지합니다.

향상된 성능:
장기간 잠그면 잠금 없이 이러한 잠금을 여러 번 획득하고 해제하는 시나리오와 비교할 때 성능이 향상됩니다.

4. 경량 및 중량 잠금장치

JVM은 스레드 간의 경합 정도에 따라 두 가지 잠금 기술을 사용합니다. 이러한 기술에는 경량 잠금 장치와 중량 잠금 장치가 포함됩니다.

경량 잠금

경량 잠금은 경합 잠금이 없을 때 발생합니다. 즉, 단 하나의 스레드만 해당 잠금을 획득하려고 합니다. 이러한 시나리오에서 JVM은 잠금을 획득하려고 할 때 CAS 작업을 사용하여 획득을 최적화하며 이는 중량 동기화 없이 발생할 수 있습니다.

헤비급 잠금

여러 스레드가 동일한 잠금을 얻으려는 경우; 즉, 경합이 있는 경우 JVM은 이를 헤비웨이트 잠금으로 에스컬레이션합니다. 여기에는 OS 수준에서 스레드를 차단하고 OS 수준 동기화 프리미티브를 사용하여 스레드를 관리하는 작업이 포함됩니다. 중량 잠금은 실제로 OS에서 컨텍스트 전환을 수행하고 스레드를 관리해야 하기 때문에 속도가 느립니다.

잠금 에스컬레이션

경량 잠금에서 경합이 발생하면 JVM이 이를 헤비급 잠금으로 에스컬레이션할 수 있습니다. 여기서 에스컬레이션은 빠른 사용자 수준 잠금에서 스레드 차단을 포함하는 더 비싼 OS 수준 잠금으로 전환하는 것을 의미합니다.

경량 잠금장치의 장점

빠른 잠금 획득: 경합이 없을 때 경량 잠금은 OS 수준 동기화를 피하기 때문에 중량 잠금보다 훨씬 빠릅니다.

차단 감소: 경합이 없으면 스레드가 차단되지 않으며 지연 시간이 줄어들면서 선형적으로 증가합니다.

무거운 자물쇠의 단점

성능 오버헤드: 중량급 잠금은 매우 높은 경합 체제에서 성능 저하와 함께 스레드 차단, 컨텍스트 전환, 스레드 깨우기 비용을 발생시킵니다.

이러한 모든 최적화는 JVM이 멀티 스레드 애플리케이션의 성능을 향상시키는 데 도움이 되므로 이제 개발자는 동기화 오버헤드를 많이 희생하지 않고도 안전한 동시 코드를 작성할 수 있습니다. 이러한 최적화를 이해하면 개발자가 특히 잠금으로 인해 성능이 저하되는 경우 더욱 효율적인 시스템을 설계하는 데 도움이 될 수 있습니다.

위 내용은 JVM 잠금 최적화 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.