자바 캐스팅으로 오버 헤드가 발생합니까? 왜?
한 유형의 객체를 다른 유형으로 캐스트 할 때 오버 헤드가 있습니까? 아니면 컴파일러가 모든 것을 해결하고 런타임에 비용이 들지 않습니까?
이것은 일반적인 것입니까, 아니면 다른 경우가 있습니까?
예를 들어, 각 요소가 다른 유형을 가질 수있는 Object []의 배열이 있다고 가정하십시오. 그러나 우리는 항상 요소 0이 Double이고 요소 1이 문자열이라는 것을 알고 있습니다. (나는 이것이 잘못된 디자인이라는 것을 알고 있지만 이것을해야한다고 가정합시다.)
Java의 유형 정보가 런타임에 계속 유지됩니까? 아니면 컴파일 후 모든 것이 잊혀지고 (Double) elements [0]을 수행하면 포인터를 따라 8 바이트를 double로 해석합니다.
Java에서 유형이 수행되는 방식에 대해 매우 명확하지 않습니다. 책이나 기사에 대한 추천이 있으면 감사합니다.
캐스팅에는 두 가지 유형이 있습니다.
암시 적 캐스팅 : 유형에서 더 넓은 유형으로 캐스트 할 때 자동으로 수행되고 오버 헤드가 없습니다.
String s = "Cast";
Object o = s; // implicit casting
더 넓은 유형에서 더 좁은 유형으로 이동할 때 명시 적 캐스팅. 이 경우 다음과 같이 캐스팅을 명시 적으로 사용해야합니다.
Object o = someObject;
String s = (String) o; // explicit casting
두 번째 경우에는 두 가지 유형을 확인해야하고 캐스팅이 가능하지 않은 경우 JVM에서 ClassCastException을 throw해야하므로 런타임에 오버 헤드가 발생합니다.
캐스팅 은 유형 간, 특히 여기서 관심이있는 캐스팅 작업 유형에 대한 참조 유형 간 변환에 사용됩니다.
업 캐스트 작업 (Java 언어 사양에서 확장 변환이라고도 함)은 하위 클래스 참조를 상위 클래스 참조로 변환합니다. 이 캐스팅 작업은 항상 안전하고 컴파일러에서 직접 구현할 수 있기 때문에 일반적으로 자동입니다.
다운 캐스트 작업 (Java 언어 사양에서 축소 변환이라고도 함)은 상위 클래스 참조를 하위 클래스 참조로 변환합니다. 이 캐스팅 작업은 실행 오버 헤드를 발생시킵니다. Java는 캐스트가 유효한지 확인하기 위해 런타임에 확인해야하기 때문입니다. 참조 된 객체가 캐스트의 대상 유형 또는 해당 유형의 서브 클래스의 인스턴스가 아닌 경우 시도 된 캐스트는 허용되지 않으며 java.lang.ClassCastException을 발생시켜야합니다.
합리적인 Java 구현을 위해 :
각 개체는 다른 것들 사이에 포함 된 헤더를 가지고, 실행시의 형태에 대한 포인터 (예를 들어 Double
나 String
있지만, 결코 수 CharSequence
또는 AbstractList
). 런타임 컴파일러 (일반적으로 Sun의 경우 HotSpot)가 유형을 정적으로 결정할 수 없다고 가정하면 생성 된 기계 코드에서 일부 검사를 수행해야합니다.
먼저 런타임 유형에 대한 포인터를 읽어야합니다. 어쨌든 비슷한 상황에서 가상 메서드를 호출하는 데 필요합니다.
클래스 유형으로 캐스팅하는 경우를 누를 때까지 정확히 몇 개의 수퍼 클래스가 있는지 알 java.lang.Object
수 있으므로 유형 포인터에서 상수 오프셋 (실제로는 HotSpot의 처음 8 개)에서 유형을 읽을 수 있습니다. 다시 말하지만 이것은 가상 메서드에 대한 메서드 포인터를 읽는 것과 유사합니다.
그런 다음 읽기 값은 예상되는 캐스트의 정적 유형과의 비교가 필요합니다. 명령어 세트 아키텍처에 따라 다른 명령어는 잘못된 분기에서 분기 (또는 오류)해야합니다. 32 비트 ARM과 같은 ISA에는 조건부 명령어가 있으며 슬픈 경로가 행복한 경로를 통과하도록 할 수 있습니다.
인터페이스의 다중 상속으로 인해 인터페이스가 더 어렵습니다. 일반적으로 인터페이스에 대한 마지막 두 개의 캐스트는 런타임 유형에 캐시됩니다. 초기 (10 년 전)에는 인터페이스가 약간 느 렸지만 더 이상 관련이 없습니다.
이런 종류의 것이 성능과 거의 관련이 없음을 알 수 있기를 바랍니다. 소스 코드가 더 중요합니다. 성능 측면에서 가장 큰 타격은 모든 곳에서 개체 포인터를 쫓아 캐시 미스가 발생하기 쉽습니다 (물론 유형 정보는 일반적입니다).
예를 들어, 각 요소가 다른 유형을 가질 수있는 Object []의 배열이 있다고 가정하십시오. 그러나 우리는 항상 요소 0이 Double이고 요소 1이 문자열이라는 것을 알고 있습니다. (나는 이것이 잘못된 디자인이라는 것을 알고 있지만 이것을해야한다고 가정합시다.)
컴파일러는 배열의 개별 요소 유형을 기록하지 않습니다. 단순히 각 요소 표현식의 유형이 배열 요소 유형에 할당 가능한지 확인합니다.
Java의 유형 정보가 런타임에 계속 유지됩니까? 아니면 컴파일 후 모든 것이 잊혀지고 (Double) elements [0]을 수행하면 포인터를 따라 8 바이트를 double로 해석합니다.
일부 정보는 런타임에 보관되지만 개별 요소의 정적 유형은 보관되지 않습니다. 클래스 파일 형식을 보면 알 수 있습니다.
이론적으로 JIT 컴파일러는 일부 할당에서 불필요한 유형 검사를 제거하기 위해 "이스케이프 분석"을 사용할 수 있습니다. 그러나 제안하는 정도까지이 작업을 수행하는 것은 현실적인 최적화의 범위를 벗어납니다. 개별 요소의 유형을 분석하는 데 따른 보상은 너무 적습니다.
게다가 사람들은 어쨌든 그렇게 응용 프로그램 코드를 작성해서는 안됩니다.
The byte code instruction for performing casting at runtime is called checkcast
. You can disassemble Java code using javap
to see what instructions are generated.
For arrays, Java keeps type information at runtime. Most of the time, the compiler will catch type errors for you, but there are cases where you will run into an ArrayStoreException
when trying to store an object in an array, but the type does not match (and the compiler didn't catch it). The Java language spec gives the following example:
class Point { int x, y; }
class ColoredPoint extends Point { int color; }
class Test {
public static void main(String[] args) {
ColoredPoint[] cpa = new ColoredPoint[10];
Point[] pa = cpa;
System.out.println(pa[1] == null);
try {
pa[0] = new Point();
} catch (ArrayStoreException e) {
System.out.println(e);
}
}
}
Point[] pa = cpa
is valid since ColoredPoint
is a subclass of Point, but pa[0] = new Point()
is not valid.
This is opposed to generic types, where there is no type information kept at runtime. The compiler inserts checkcast
instructions where necessary.
This difference in typing for generic types and arrays makes it often unsuitable to mix arrays and generic types.
In theory, there is overhead introduced. However, modern JVMs are smart. Each implementation is different, but it is not unreasonable to assume that there could exist an implementation that JIT optimized away casting checks when it could guarantee that there would never be a conflict. As for which specific JVMs offer this, I couldn't tell you. I must admit I'd like to know the specifics of JIT optimization myself, but these are for JVM engineers to worry about.
The moral of the story is to write understandable code first. If you're experiencing slowdowns, profile and identify your problem. Odds are good that it won't be due to casting. Never sacrifice clean, safe code in an attempt to optimize it UNTIL YOU KNOW YOU NEED TO.
참고URL : https://stackoverflow.com/questions/2170872/does-java-casting-introduce-overhead-why
'program story' 카테고리의 다른 글
"지정된 경로의 형식은 지원되지 않습니다." (0) | 2020.08.28 |
---|---|
NSAutoreleasePool 자동 릴리스 풀은 어떻게 작동합니까? (0) | 2020.08.27 |
대부분의 프린터에서 처리 할 수있는 최소 여백은 얼마입니까? (0) | 2020.08.27 |
슬라이스에서 요소 위치를 찾는 방법은 무엇입니까? (0) | 2020.08.27 |
Visual Studio 2012의 '백그라운드 작업 대기'란 무엇입니까? (0) | 2020.08.27 |