2011-08-16 2 views
3

어떤 사람이 어떤 최적화에 대한 정보를 가지고 있습니까 (구현에 따라 다르다는 것을 알고 있습니다). 대부분의 JVM은 최종 객체에 직면했을 때 어떻게됩니까? 특히, 자바에서 최종 객체의 배열?Java의 "final"클래스를 일부 JVM에서 다르게 할당 할 수 있습니까?

final class A { } 
A myArray[] = new A[10]; 

만약 클래스 "A"는이 더 서브 클래스를 가질 수 후 최종, 그래서 전체 배열을 (생성자를 호출하지 않음) 할당 할 수있을 것처럼 보인다 (즉, malloc을 (를 sizeof (A : 예를 들어,) * 10)) 가비지 콜렉션/책 보관에 저장하십시오.

+0

JVM 구현 문제 - 내부적으로 메모리를 처리하는 방법과 가비지 수집에 영향을 미칠 수 있습니까? 이는 메모리가 Java에 어떻게 표시되는지와 다릅니다. – user611942

답변

2

나는 모든 JVM이 그렇게하기를 귀찮게 생각합니다. 부분적으로는 아마도 여분의 책을 보관할 것이기 때문입니다. 모든 인스턴스가 배열에 있고 JVM의 규칙과 일치하도록 이중으로 수정해야하는 경우가 있습니다.

예 :

final class A { 
    String value = "default"; 
} 

A instance = new A(); 
A[] array = new A[] {instance}; 
instance.value = "another value"; 
assert instance == array[0]; 
assert instance.value == array[0].value; 

배열을 따라서는 A.

의 다른 인스턴스에서 변경 될 때마다 value의 내용을 변경해야하는 JVM을 강제로 작성 될 때 instance의 사본을 강제 제안 구현이 생성 될 흥미로운 생각과 어느 정도 일 것이다

: 귀하의 코멘트에 대한 응답으로


. 그러나 당신의 아이디어는 가비지 컬렉터 성능을 파괴 할 것입니다. 그 이유는 최고의 JVM은 참조 횟수를 사용하지 않기 때문입니다. 가장 좋은 JVM은 moving garbage collector을 사용합니다. 이 기법은 참조되는 객체를보기 위해 모든 루트 노드 (예 : 스레드)를 추적합니다. 참조 체인의 모든 객체는 연속 블록으로 이동됩니다. 이 블록 외부의 모든 메모리는 비어있는 것으로 간주됩니다. dealloc이나 finalize 또는 아무것도 호출하지 않습니다. 이 기술은 매우 빠릅니다 (일부는 GCed 언어로 된 객체의 "유아 사망률"이 높기 때문 임). 더 많은 것은이 기술이 순환 참조를 검사 할 필요가 없다는 것입니다.

로 돌아 가기 : 배열이 범위를 벗어 났을 때 JVM은 배열의 요소에 대한 다른 참조가 있는지 확인하고 배열의 메모리를 확보하기 전에 이러한 객체에 대한 malloc 새 공간을 확인해야합니다 . 이렇게하면 "이동하는 가비지 컬렉터"를 사용할 수 없으며 참조 계산과 같은 비효율적 인 GC 기술로 돌아 가야합니다.그래서 당신의 아이디어가 언뜻보기에는 좋지만 (특정 에지 경우에만), 더 광범위하게 적용될 수 있고 훨씬 더 효율적인 효율성을 제공 할 수있는 다른 GC 전략을 방해합니다.

+0

아니, 나는 그런 경우는 아니라고 생각한다 - 당신은 단지 하나의 사본으로 만 할 수있다. 배열 요소의 할당은 지연된 초기화로 한 번의 작업에서 발생합니다. JVM은 이미 참조가있는 간접 계층을 가져야하므로 할당시 위치를 업데이트 할 수 있어야합니다 (GC 중 오브젝트를 이동하는 경우). – user611942

+0

@ user611942 나는 당신의 아이디어를 고려해 메인 포스트에서 대답했다. – Dunes

+0

감사의 듄 - JDK 소스를 간략하게 살펴본 결과, 컴파일 단계에서 final의 특별한 처리가없는 것처럼 보입니다. 출력에서 ​​최종 태그가 붙은 것처럼 보일 수도 있습니다. 나는 영리함의 대부분이 가상 머신에있을 것이라고 생각하고있다. 나는 당신의 답을 옳은 것으로 표시 할 것인데, 아무도 "최종"에 의해 최적화가 가능 해지는 것에 대한 확실한 답을 얻지 못한 것 같다. – user611942

1

JVM (또는 컴파일러가 더 정확함)이하는 최종 키워드에 대한 최적화가 경우마다 다릅니다.

  1. 일반적으로 좋은 방법은 모든 메소드 변수를 파일로 선언하는 것입니다 (메소드 내에서 변경하지 않는 한). 이제 컴파일러 (jvm이 아님)가하는 일은 해당 변수의 모든 발생을 해당 값으로 대체하는 것입니다 (최종으로 변경되지 않음).

  2. myArray[] = new A[10];의 경우 배열 참조는 최종 값이며 배열 값은 아닙니다.

  3. final class A { }의 경우 클래스가 서브 클래 싱되지 못하게하는 디자인 제약 조건입니다.

    그래서 이것들을 살펴보면 final에 대한 최적화가 대부분 컴파일러에 의해 수행되고 따라서 구현간에 동일해야합니다.

+0

질문은 - 그 최적화는 무엇입니까? – user611942

+1

http://renaud.waldura.com/doc/java/final-keyword.shtml 링크를 확인하십시오. 여기에는 성능 최적화에 대한 세부 정보가 있습니다. – Santosh

+0

한 번 더 링크 : http://www.javaperformancetuning.com/tips/final.shtml – Santosh

1

Java로 배열을 만들 때. 요소 인스턴스가 생성되지 않습니다! 자바 인스턴스는 C와 같은 구조체가 아니며 배열에 대해 복사되거나 할당됩니다 (배열에는 참조 만 포함). 따라서 요소 유형이 최종 유형인지 여부는 차이가 없습니다.

A[] myArray = new A[10]; 

myArray[n]

후에는 항상 null입니다! 그 후에 요소를 할당 할 수 있습니다.

myArray[0] = new A(); 
+0

Arne에게 감사 드려요.하지만 수업이 끝나면 최적화가 가능해집니다. 이 최적화는 Java 수준에서 노출되지 않습니다. 즉, 항상 null로 표시됩니다. JVM 내에서 전체 블록은 한 번에 할당되어 초기화되지 않았으므로 GC로드가 줄어 듭니다. 큰 오브젝트의 경우 이것은 나쁜 생각 일 수 있지만, 작은 클래스의 경우 큰 이점이 될 수 있습니다. 문제는 "최종"클래스에 직면했을 때 JVM이 내부적으로 수행하는 최적화는 무엇입니까? – user611942

0

저는 오늘 최종 방법에서 최대 reading입니다. 그리고 클래스 최종을 선언하는 것은 모든 메소드를 최종적으로 선언하기위한 짧은 손일뿐입니다.

방법 최종 선언의 장점은 컴파일러가 메소드를 디스패치 할 때 가상 테이블 룩업을 이용하여 회피 할 수 있다는 것이다 -. 즉,이 방법에서 찾아 볼 수있는 클래스를 정확하게 알고

Java 메소드는 기본적으로 가상 메소드이며, C++에서는 그 반대가 사실입니다. Java에서 가상이 아닌 유일한 메소드는 정적 메소드와 최종 메소드입니다.

최종 메서드를 명시 적으로 선언함으로써 얻는 성능상의 이점에 대해서는 논쟁의 여지가 있습니다. 훌륭한 JIT 컴파일러는 코드를 분석하고 유용하다고 판단되는 최적화를 수행 할 수 있습니다. 클래스 A에 현재로드 된 하위 클래스가없는 경우 자주 호출되는 경우 JIT 컴파일러는 A 인스턴스의 메서드를 호출하는 코드 경로를 최적화하도록 결정할 수 있습니다. 여기에는 vtable 조회를 없애거나 메소드 호출을 인라이닝하는 것이 포함됩니다.

예 : 다음 코드 경로는 메서드를 빠르게 실행하면 최적화 할 수있는 좋은 방법입니다. 방법을 재정의하는의 서브 클래스가 이후에로드 된 경우

public void run(A instance) { 
    while (true) { 
     instance.method(); 
    } 
} 

다음 JIT 컴파일러는 메소드의 호출에 관하여 한 모든 최적화를 무효화 할 수 있습니다.

본질적으로 훌륭한 JIT는 실제로 최종적인 것을 선언하지 않고도 최종 선언문의 모든 장점을 제공 할 수 있습니다. 그리고 우리는 최종적인 것을 선언 할 필요가 없기 때문에 어떤 클래스 나 메소드가 최종적인 것인지 걱정할 필요없이 완전히 객체 지향적 인 접근 방식으로 자유롭게 개발할 수 있습니다. 따라서 final은 문서화 목적으로 만 사용해야합니다. 한 가지 예외는이 필드를 사용하여 메모 작성의 후보로 표시된 모든 계산 즉, 결과를 캐싱하고 계산을 다시 수행하는 대신 캐시 된 결과를 사용한다는 것입니다.

+0

감사의 말 - 런타임 프로파일 링 및 동적 재 컴파일을 사용하면 정적으로 컴파일 된 언어에서 최적화를 위해 많은 양의 태그 지정이 필요하지 않습니다. (처음 몇 번의 실행에서는 심각한 히트가 있을지 모르겠지만). C++에서 final은 "const"와 매우 흡사합니다. 실제로 성능 향상에 도움이되는 것보다 훨씬 많은 문서를 지원합니다. 따라서 특정 최적화가 없습니다. 최종 오브젝트의 배열의 선언 런타임시 JVM이 코드로 수행하기로 결정한 것에 완전히 의존합니다. – user611942

관련 문제