자격을 갖춘 Java 개발자로서 우리 모두는 기본적으로 모든 객체가 힙에 생성된다는 것을 알고 있습니다. 그러나 여기에는 아직 절대적인 단어가 없으며 기본적으로 모든 것을 의미합니다.
어제 인터뷰 중 친구가 모든 객체는 힙에서 생성된다고 말하며 면접관을 비웃었습니다.
오늘은 본문을 시작으로 탈출 분석에 대해 이야기해 보겠습니다.
Escape Analysis(Escape Analysis)는 현재 Java 가상 머신에서 비교적 최첨단 최적화 기술입니다. 이는 Java 프로그램의 동기화 부하 및 메모리 힙 할당 부담을 효과적으로 줄일 수 있는 교차 기능 전역 데이터 흐름 분석 알고리즘입니다. Java Hotspot 컴파일러는 이스케이프 분석을 통해 새 개체 참조의 사용 범위를 분석하고 이 개체를 힙에 할당할지 여부를 결정할 수 있습니다.
이스케이프 분석의 기본 원칙은 : 객체의 동적 범위를 분석하는 것입니다. 객체가 메소드에 정의되면 호출 매개변수로 다른 메소드에 전달되는 등 외부 메소드에 의해 참조될 수 있습니다. 메소드 이스케이프는 다른 스레드에서 액세스할 수 있는 인스턴스 변수에 할당하는 것과 같이 외부 스레드에 의해 액세스될 수도 있습니다. 높은 수준의 탈출.
이스케이프 분석이 켜져 있으면 컴파일러는 다음과 같이 코드를 최적화할 수 있습니다:
JVM에서는 다음 매개변수를 통해 이스케이프 분석 활성화 여부를 지정할 수 있습니다.
-XX:+DoEscapeAnalytic
: 이스케이프 분석이 켜져 있음을 나타냅니다(JDK 1.7 이후에는 기본적으로 켜져 있음). -XX:+DoEscapeAnalysis
:表示开启逃逸分析(JDK 1.7之后默认开启)。
-XX:-DoEscapeAnalysis
스레드 동기화 자체는 상대적으로 시간이 많이 걸리는 프로세스입니다. 이스케이프 분석을 통해 변수가 스레드를 탈출하지 않고 다른 스레드에서 액세스할 수 없다고 판단하면 읽기 및 쓰기가 전혀 발생하지 않습니다. 경쟁이 발생하면 이 변수에 구현된 동기화 조치를 안전하게 제거할 수 있습니다.
다음 코드는
public void method() { Object o = new Object(); synchronized (o) { System.out.println(o); } }
잠금对象o
이지만 객체 o의 수명 주기는 method() 메서드와 동일하므로 다른 스레드에서 액세스할 수 없으며 스레드 안전 문제가 발생하지 않습니다. JIT 컴파일 단계에서 차단됩니다. 다음과 같이 최적화되었습니다.
public void method() { Object o = new Object(); System.out.println(o); }
이를 Lock Elimination이라고도 합니다.
Java 가상 머신에서 Java 힙에 생성된 객체에 대한 메모리 공간을 할당하는 것은 Java 프로그래머에게 거의 상식입니다. 이 객체에 대한 참조를 보유하고 있는 한 힙에 저장된 객체 데이터에 액세스할 수 있습니다. 가상 머신의 가비지 수집 하위 시스템은 더 이상 힙에서 사용되지 않는 개체를 재활용하지만, 재활용 가능한 개체를 표시하고 필터링하거나 메모리를 재활용하고 구성하는 재활용 작업에는 많은 리소스가 필요합니다. 그러나 특별한 경우가 있습니다. 이스케이프 분석을 통해 개체가 스레드 외부로 이스케이프되지 않는 것으로 확인되면 스택에 할당하도록 최적화될 수 있습니다. 이렇게 하면 힙에 메모리를 할당할 필요가 없고 가비지 수집도 필요하지 않습니다.
다음 코드와 같습니다:
public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 1000000; i++) { alloc(); } Thread.sleep(100000); } private static void alloc() { User user = new User(); }
코드는 매우 간단합니다. 루프를 100만 번 생성하고 alloc() 메서드를 사용하여 100만 개의 User 객체를 생성하는 것입니다. 여기서 alloc() 메소드에 정의된 User 객체는 다른 메소드에서 참조되지 않으므로 스택 할당 요구 사항을 충족합니다.
JVM 매개변수는 다음과 같습니다.
-Xmx2G -Xms2G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
프로그램을 시작하고 jmap 도구를 통해 인스턴스 수를 확인합니다.
jmap -histo pid num #instances #bytes class name ---------------------------------------------- 1: 3771 2198552 [B 2: 10617 1722664 [C 3: 104057 1664912 com.miracle.current.lock.StackAllocationTest$User
프로그램이 총 104057개의 사용자 개체를 생성한 것을 볼 수 있습니다. 이는 1보다 훨씬 적습니다. 백만. 탈출 분석을 끄고 다시 살펴볼 수 있습니다:
-Xmx2G -Xms2G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
프로그램을 시작하고 jmap 도구를 통해 인스턴스 수를 확인하십시오:
jmap -histo 42928 num #instances #bytes class name ---------------------------------------------- 1: 628 22299176 [I 2: 1000000 16000000 com.miracle.current.lock.StackAllocationTest$User
탈출 분석을 끈 후 총 100만 개의 사용자 개체가 생성된 것을 볼 수 있습니다. . 이에 비해 스택 할당은 힙 메모리 소비 및 GC에서 중요한 역할을 합니다.
데이터를 더 이상 더 작은 데이터로 분해하여 표현할 수 없는 경우 Java 가상 머신의 원래 데이터 유형(int, long 및 기타 숫자 유형 및 참조 유형 등)은 사용할 수 없습니다. 더 분해되면 이러한 데이터를 스칼라라고 부를 수 있습니다. 반대로, 데이터 조각이 계속해서 분해될 수 있는 경우 이를 집계라고 합니다. Java의 개체는 일반적인 집계입니다.
이스케이프 분석을 통해 객체가 메서드 외부에서 액세스되지 않고 이 객체가 해체될 수 있음을 증명할 수 있다면 프로그램은 실제로 실행될 때 이 객체를 생성하지 않고 대신에 사용할 여러 객체를 직접 생성할 수 있습니다. 대신 이 메서드를 사용하세요.
다음 코드가 있습니다:
public static void main(String[] args) { method(); } private static void method() { User user = new User(25); System.out.println(user.age); } private static class User { private int age; public User(int age) { this.age = age; } }
在method()
方法中创建User对象,指定age为25,这里User不会被其他方法引用,也就是说它不会逃逸出方法,并且User是可以拆解为标量的。所以alloc()
代码会优化为如下:
private static void alloc() { int age = 25; System.out.println(age); }
尽管目前逃逸分析技术仍在发展之中,未完全成熟,但它是即时编译器优化技术的一个重要前进方向,在日后的Java虚拟机中,逃逸分析技术肯定会支撑起一系列更实用、有效的优化技术。
위 내용은 3분 만에 JVM 이스케이프 분석 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!