>  기사  >  Java  >  Java에서 이스케이프를 이해하는 방법

Java에서 이스케이프를 이해하는 방법

WBOY
WBOY앞으로
2023-04-28 19:19:04856검색

Java 컴파일 시스템에서 Java 소스 코드 파일을 컴퓨터에서 실행 가능한 기계 명령으로 변환하는 프로세스에는 두 가지 컴파일 단계가 필요합니다. 첫 번째 단계는 .java 파일을 .class 파일로 변환하는 것입니다. 컴파일의 두 번째 단계는 .class를 기계 명령어로 변환하는 프로세스입니다.

컴파일의 첫 번째 섹션은 javac 명령입니다.

두 번째 컴파일 단계에서 JVM은 바이트코드를 해석하고 이를 해당 기계 명령어로 변환하고 이를 하나씩 읽고 번역을 하나씩 해석합니다. 분명히, 해석 및 실행 후에는 실행 속도가 실행 가능한 바이너리 바이트코드 프로그램보다 필연적으로 훨씬 느려질 것입니다. 이는 전통적인 JVM 인터프리터(Interpreter)의 기능이다. 이러한 효율성 문제를 해결하기 위해 JIT(Just In Time Compilation) 기술이 도입되었습니다.

JIT 기술이 도입된 후에도 Java 프로그램은 여전히 ​​인터프리터를 통해 해석되고 실행됩니다. JVM은 특정 메서드나 코드 블록이 특히 자주 실행되는 것을 발견하면 이를 "핫스팟 코드"로 간주합니다. 그런 다음 JIT는 일부 "핫 코드"를 로컬 시스템과 관련된 기계 코드로 변환하고 최적화한 다음 다음 사용을 위해 번역된 기계 코드를 캐시합니다.

Java 컴파일 원리에 대한 심층 분석에서 JIT 컴파일 및 핫스팟 감지 내용을 이미 소개했으므로 여기서는 주로 JIT의 최적화에 대해 자세히 설명하지 않겠습니다. JIT 최적화의 가장 중요한 측면 중 하나는 탈출 분석입니다.

탈출 분석

이스케이프 분석의 개념과 관련하여 모든 객체와 배열이 힙에 메모리를 할당하는 것은 아니라는 사실을 참고할 수 있습니다. 다음은 간단한 리뷰입니다.

이스케이프 분석의 기본 동작은 개체의 동적 범위를 분석하는 것입니다. 개체가 메서드에 정의되면 메서드라고 하는 호출 매개 변수로 다른 위치에 전달되는 등 외부 메서드에 의해 참조될 수 있습니다. 탈출하다.

예를 들어 다음 코드는 다음과 같습니다.

공개 정적 StringBuffer craeteStringBuffer(문자열 s1, 문자열 s2) {

StringBuffer sb = 새로운 StringBuffer();

sb.append(s1);

sb.append(s2);

반납;

}

공개 정적 문자열 createStringBuffer(문자열 s1, 문자열 s2) {

StringBuffer sb = 새로운 StringBuffer();

sb.append(s1);

sb.append(s2);

sb.toString()을 반환합니다.

}

첫 번째 코드의 sb는 이스케이프되지만 두 번째 코드의 sb는 이스케이프되지 않습니다.

이스케이프 분석을 사용하여 컴파일러는 다음과 같이 코드를 최적화할 수 있습니다. 1. 동기화가 생략됩니다. 하나의 스레드에서만 개체에 액세스할 수 있는 것으로 확인되면 이 개체에 대한 작업에 대해 동기화가 고려되지 않을 수 있습니다.

2. 힙 할당을 스택 할당으로 변환합니다. 개체에 대한 포인터가 절대 이스케이프되지 않도록 개체가 서브루틴에 할당된 경우 해당 개체는 힙 할당이 아닌 스택 할당의 후보가 될 수 있습니다.

3. 객체를 분리하거나 스칼라 대체합니다. 일부 개체는 액세스하기 위해 연속적인 메모리 구조로 존재할 필요가 없으므로 개체의 일부(또는 전체)가 메모리에 저장되지 않고 CPU 레지스터에 저장될 수 있습니다.

Java 코드가 실행 중일 때 JVM 매개변수를 통해 이스케이프 분석 활성화 여부를 지정할 수 있습니다.

-XX:+DoEscapeAnalytic: 탈출 분석이 켜져 있음을 나타냅니다

-XX:-DoEscapeAnalytic: 이스케이프 분석이 jdk 1.7부터 기본적으로 시작되었음을 나타냅니다. 이 기능을 끄려면 -XX:-DoEscapeAnalytic

을 지정해야 합니다. 동기화 생략

동기화된 블록을 동적으로 컴파일할 때 JIT 컴파일러는 이스케이프 분석을 사용하여 동기화된 블록에서 사용하는 잠금 개체가 한 스레드에서만 액세스할 수 있고 다른 스레드에서는 해제되지 않았는지 여부를 확인할 수 있습니다.

이 분석을 통해 동기화된 블록이 사용하는 잠금 개체가 하나의 스레드에서만 액세스 가능한 것으로 확인되면 JIT 컴파일러는 동기화된 블록을 컴파일할 때 코드의 이 부분을 비동기화합니다. 이러한 동기화 취소 프로세스를 동기화 생략, 잠금 제거라고도 합니다.

다음 코드와 같습니다:

공개 무효 f() {

객체 홀리스 = new Object();

동기화(홀리스) {

System.out.println(hollis);

}

}

hollis 개체는 코드에서 잠겨 있지만 hollis 개체의 수명 주기는 f() 메서드에만 있고 다른 스레드에서는 액세스할 수 없으므로 JIT 컴파일 단계에서 최적화됩니다. 최적화:

공개 무효 f() {

객체 홀리스 = new Object();

System.out.println(hollis);

}

따라서 동기화를 사용할 때 JIT가 이스케이프 분석 후 스레드 안전 문제가 없는 것으로 확인되면 잠금을 제거합니다.

스칼라 대체

스칼라는 더 작은 데이터로 나눌 수 없는 데이터를 말합니다. Java의 기본 데이터 유형은 스칼라입니다. 대조적으로, 분해될 수 있는 데이터를 집계라고 합니다. Java의 객체는 다른 집계 및 스칼라로 분해될 수 있기 때문에 집계입니다.

JIT 단계에서 이스케이프 분석을 통해 객체가 외부 세계에서 접근할 수 없다는 것이 발견되면 JIT 최적화 후 객체는 그 안에 포함된 여러 멤버 변수로 분해되어 교체됩니다. 이 과정은 스칼라 대체입니다.

공개 정적 무효 메인(문자열[] args) {

할당();

}

개인 정적 무효 할당() {

포인트 포인트 = new Point(1,2);

System.out.println("point.x="+point.x+"; point.y="+point.y);

}

수업 포인트{

개인 정수 x;

비공개 int y;

}

위 코드에서 포인트 객체는 alloc 메서드를 벗어나지 않으며, 포인트 객체는 스칼라로 분해될 수 있습니다. 그런 다음 JIT는 Point 개체를 직접 생성하지 않고 두 개의 스칼라 int x 및 int y를 직접 사용하여 Point 개체를 대체합니다.

스칼라 교체 후 위 코드는 다음과 같습니다.

개인 정적 무효 할당() {

정수 x = 1;

정수 y = 2;

System.out.println("point.x="+x+"; point.y="+y);

}

집계수량 Point의 이탈분석 결과 이탈하지 않은 것으로 확인되어 집계수량 2개로 대체되었음을 알 수 있다. 그렇다면 스칼라 대체의 이점은 무엇입니까? 즉, 힙 메모리 사용량을 크게 줄일 수 있습니다. 일단 객체를 생성할 필요가 없기 때문에 힙 메모리를 할당할 필요가 없습니다.

스칼라 대체는 스택 할당을 위한 좋은 기반을 제공합니다.

스택에 할당

JVM(Java Virtual Machine)에서는 객체가 Java 힙에 메모리를 할당받는 것이 상식입니다. 그러나 특별한 경우가 있습니다. 즉, 이스케이프 분석 후 개체에 이스케이프 메서드가 없는 것으로 발견되면 스택에 할당하도록 최적화될 수 있습니다. 이렇게 하면 힙에 메모리를 할당할 필요가 없고 가비지 수집도 필요하지 않습니다.

스택 할당에 대한 자세한 소개는 모든 객체와 배열이 힙에 메모리를 할당하는 것은 아닙니다를 참조하세요. .

여기서는 기존 가상머신에서는 스택에 대한 할당이 실제로 구현되지 않고, 객체와 배열이 모두 힙에 할당되지 않는다는 점을 간략하게 언급하고 싶습니다. 이 예에서는 객체가 힙에 할당되지 않고 실제로 스칼라 대체에 의해 구현됩니다.

탈출 분석이 성숙하지 않았습니다

탈출 분석에 관한 논문은 1999년에 발표되었지만 JDK 1.6까지는 구현되지 않았으며 이 기술은 아직 성숙하지 않았습니다.

근본적인 이유는 이탈 분석의 성능 소모가 소모 분석의 성능 소모보다 높을 것이라는 보장이 없기 때문입니다. 이스케이프 분석은 스칼라 대체, 스택 할당 및 잠금 제거를 수행할 수 있습니다. 그러나 탈출 분석 자체에도 일련의 복잡한 분석이 필요하며 이는 실제로 상대적으로 시간이 많이 걸리는 프로세스입니다.

극단적인 예는 탈출 분석 결과 탈출하지 않는 객체가 없다는 것을 발견한 것이다. 그러면 탈출 분석 과정이 낭비됩니다.

이 기술은 아직 성숙되지는 않았지만 JIT(Just-In-Time) 컴파일러 최적화 기술에 있어 매우 중요한 수단이기도 합니다.

위 내용은 Java에서 이스케이프를 이해하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제