Java에서 final 키워드를 사용하면 퍼포먼스가 향상됩니까?
에서는 바에서 in in in where where where where where where where where where where where where where where where where where where where where where where where where where where 가 많은 곳을 볼 수 있습니다.final
키워드를 사용할 수 있지만, 그 사용은 일반적이지 않습니다.
예를 들어 다음과 같습니다.
String str = "abc";
System.out.println(str);
의 경우, 「」는,str
수 있습니다.final
하지만 이것은 보통 생략된다.
메서드가 덮어쓰기되지 않을 경우 final 키워드를 사용할 수 있습니다.상속되지 않는 클래스의 경우도 마찬가지입니다.
이러한 경우에 final 키워드를 사용하면 실제로 퍼포먼스가 향상됩니까?렇면면면면면면?설명해 주세요.「 」의 .final
퍼포먼스에 있어서 매우 중요한데, 자바 프로그래머가 키워드를 가장 잘 사용하기 위해 어떤 습관을 길러야 하는가?
보통은 그렇지 않아요.가상 메서드의 경우 HotSpot은 메서드가 실제로 재정의되었는지 여부를 추적하고 메서드를 재정의하는 클래스를 로드할 때까지 메서드가 재정의되지 않았다는 가정 하에 인라인과 같은 최적화를 수행할 수 있습니다. 이 경우 HotSpot은 이러한 최적화를 실행 취소(또는 부분적으로 취소)할 수 있습니다.
(물론 HotSpot을 사용하고 있다고 가정합니다만, 지금까지 가장 일반적인 JVM이기 때문에...)
내 생각에 너는 그것을 사용해야 한다.final
명확한 설계와 가독성에 근거하고 있습니다.성능상의 이유로 변경하려는 경우 가장 선명한 코드를 구부리기 전에 적절한 측정을 수행해야 합니다. 내 그것은 없다. (YMMV.)YMMV)
편집: 최종 필드는 이미 언급되었듯이, 명확한 디자인 측면에서 어쨌든 좋은 아이디어인 경우가 많습니다.또한 크로스 스레드 가시성 측면에서 보장된 동작을 변경합니다. 즉, 컨스트럭터가 완료된 후에는 다른 스레드에서 최종 필드를 즉시 볼 수 있습니다.은 아마 가장 입니다.final
을 위한 하지만, 는 아마도 " 블로흐"를 사용해야 할 이다.final
★★★★★★★★★★★★★...
간단한 답변: 걱정하지 마세요!
장황한 답변:
최종 로컬 변수에 대해 설명할 때 키워드를 사용하면final
컴파일러가 코드를 정적으로 최적화하는 데 도움이 되고 결과적으로 코드가 빨라질 수 있습니다.예를 들어, 마지막 문자열은a + b
다음 예시는 (컴파일 시) 정적으로 연결되어 있습니다.
public class FinalTest {
public static final int N_ITERATIONS = 1000000;
public static String testFinal() {
final String a = "a";
final String b = "b";
return a + b;
}
public static String testNonFinal() {
String a = "a";
String b = "b";
return a + b;
}
public static void main(String[] args) {
long tStart, tElapsed;
tStart = System.currentTimeMillis();
for (int i = 0; i < N_ITERATIONS; i++)
testFinal();
tElapsed = System.currentTimeMillis() - tStart;
System.out.println("Method with finals took " + tElapsed + " ms");
tStart = System.currentTimeMillis();
for (int i = 0; i < N_ITERATIONS; i++)
testNonFinal();
tElapsed = System.currentTimeMillis() - tStart;
System.out.println("Method without finals took " + tElapsed + " ms");
}
}
결과는?
Method with finals took 5 ms
Method without finals took 273 ms
Java Hotspot VM 1.7.0_45-b18에서 테스트 완료.
그렇다면 실제 성능 향상은 얼마나 될까요?감히 말할 수 없다.대부분의 경우 한계(이 합성 테스트에서는 문자열 연결이 모두 회피되기 때문에 약 270나노초)이지만, 매우 최적화된 유틸리티 코드에서는 요인이 될 수 있습니다.어떤 경우에도 원래 질문에 대한 대답은 "예"입니다. 그러면 성능이 향상될 수 있지만 기껏해야 약간만 개선될 수 있습니다.
컴파일 의 메리트는 차치하고, 「」의 이, 「」의 증거는 찾을 수 .final
퍼포먼스에 측정 가능한 영향을 미칩니다.
네, 할 수 있어요.최종 결과로 퍼포먼스가 향상되는 예를 다음에 제시하겠습니다.
조건부 컴파일은 특정 조건에 따라 코드 행이 클래스 파일로 컴파일되지 않는 기술입니다.이를 통해 프로덕션 빌드에서 대량의 디버깅 코드를 제거할 수 있습니다.
다음 사항을 고려하십시오.
public class ConditionalCompile {
private final static boolean doSomething= false;
if (doSomething) {
// do first part.
}
if (doSomething) {
// do second part.
}
if (doSomething) {
// do third part.
}
if (doSomething) {
// do finalization part.
}
}
doSomething 속성을 최종 속성으로 변환함으로써 컴파일러는 doSomething을 볼 때마다 컴파일 시간 대체 규칙에 따라 false로 대체해야 한다고 말합니다.컴파일러의 첫 번째 패스는 코드를 다음과 같이 변경합니다.
public class ConditionalCompile {
private final static boolean doSomething= false;
if (false){
// do first part.
}
if (false){
// do second part.
}
if (false){
// do third part.
}
if (false){
// do finalization part.
}
}
이 작업이 완료되면 컴파일러는 다시 한 번 확인하고 코드에 도달할 수 없는 스테이트먼트가 있음을 확인합니다.최고 품질의 컴파일러를 사용하고 있기 때문에 도달할 수 없는 바이트 코드를 모두 좋아하지 않습니다.이 경우, 다음과 같은 결과가 됩니다.
public class ConditionalCompile {
private final static boolean doSomething= false;
public static void someMethodBetter( ) {
// do first part.
// do second part.
// do third part.
// do finalization part.
}
}
따라서 과도한 코드나 불필요한 조건부 체크를 줄일 수 있습니다.
편집: 예를 들어 다음 코드를 예로 들어 보겠습니다.
public class Test {
public static final void main(String[] args) {
boolean x = false;
if (x) {
System.out.println("x");
}
final boolean y = false;
if (y) {
System.out.println("y");
}
if (false) {
System.out.println("z");
}
}
}
에서 이 8에서 할 때javap -c Test.class
을 사용하다
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static final void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: ifeq 14
6: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
9: ldc #22 // String x
11: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
14: iconst_0
15: istore_2
16: return
}
에는 최종 가 아닌 변수만 되어 있습니다.x
이 때문에 적어도 이 간단한 경우 최종 변수가 성능에 영향을 미칠 수 있습니다.
IBM에 따르면 클래스나 메서드에는 해당되지 않습니다.
http://www.ibm.com/developerworks/java/library/j-jtp04223.html
나는 아무도 적어도 약간의 작은 차이가 있다는 것을 증명하기 위해 디컴파일된 실제 코드를 게시하지 않았다는 것에 놀랐다.
은 고고참 for for against에 대해 되었습니다.javac
버전8
,9
그리고.10
.
다음과 같은 방법을 가정합니다.
public static int test() {
/* final */ Object left = new Object();
Object right = new Object();
return left.hashCode() + right.hashCode();
}
이 코드를 그대로 컴파일하면 다음과 같은 바이트 코드가 생성됩니다.final
존재했을 것이다.final Object left = new Object();
).
하지만 이건...
public static int test() {
/* final */ int left = 11;
int right = 12;
return left + right;
}
작성:
0: bipush 11
2: istore_0
3: bipush 12
5: istore_1
6: iload_0
7: iload_1
8: iadd
9: ireturn
떠나는final
현재 생산량:
0: bipush 12
2: istore_1
3: bipush 11
5: iload_1
6: iadd
7: ireturn
이 코드는 컴파일 시간 상수가 있는 경우 오퍼랜드스택에 직접 로드됩니다(앞의 예시와 같이 로컬 변수 배열에 저장되지 않습니다).bipush 12; istore_0; iload_0
아무도 바꿀 수 없으니 말이 되네
한편, 왜 컴파일러가 두 번째 케이스에서istore_0 ... iload_0
내 능력 밖이야, 그 슬롯이랑은 달라0
는 어떤 방법으로도 사용됩니다(변수 배열을 이렇게 축소할 수 있지만 IM에 내부 상세 정보가 누락되어 있을 수 있습니다.확실히 알 수 없습니다).
이런 최적화를 보고 깜짝 놀랐어요. 어린애들이 얼마나javac
그렇습니다. 항상 사용되어야 하는 것입니다.final
? 난 심지어 글도 쓰지 않을 거야.JMH
테스트(처음 하고 싶었던 것)의 순서에는 차이가 있습니다.ns
(가능한 한 캡처할 수 있습니다).이것이 문제가 될 수 있는 유일한 장소는 메서드의 크기(및 선언)로 인해 인라인화할 수 없는 경우입니다.final
그 사이즈를 몇 바이트 축소합니다).
두 개 더 있다final
대처가 필요한 것.첫 번째는 어떤 방법이final
(에서)JIT
perspective)) 이러한 방법은 단일형입니다. 그리고 이것들은 가장 사랑받는 것입니다.JVM
.
그럼 거기엔final
인스턴스 변수(모든 컨스트럭터에서 설정되어야 함).이러한 변수들은 여기서 살짝 터치한 것처럼 정확하게 지정된 참조를 보증하기 때문에 중요합니다.JLS
.
즉, 여기에 있는 모든 답변에는 보이지 않는 것이 하나 더 있습니다.garbage collection
설명하려면 시간이 많이 걸리겠지만 변수를 읽으면GC
소위 말하는 것이 있다barrier
그 독서에 써주세요.모든aload
그리고.getField
그런 장벽을 통해 "보호"되고 있습니다. 자세한 내용은 여기를 참조하십시오.이론상으로는final
필드에는 이러한 "보호"가 필요하지 않습니다(장애물을 완전히 건너뛸 수 있습니다).만약 GC가 그렇게 한다면-final
퍼포먼스가 향상됩니다.
당신은 정말로 두 가지 다른 경우에 대해 묻고 있습니다.
final
로컬 변수의 경우final
메서드/프로세서용
Jon Sket은 이미 2)에 답했습니다.1)에 대해서:
차이가 없다고 생각합니다. 로컬 변수의 경우 컴파일러는 변수가 최종 변수인지 아닌지를 추론할 수 있습니다(단순히 변수가 여러 번 할당되었는지 확인하는 것).따라서 컴파일러가 한 번만 할당된 변수를 최적화하려면 변수가 실제로 선언되었는지 여부에 관계없이 그렇게 할 수 있습니다.final
그렇지 않으면.
final
는 보호 클래스 또는 퍼블릭클래스 필드에 차이가 있을 수 있습니다.컴파일러가 필드가 여러 번 설정되어 있는지 여부를 판별하는 것은 매우 어렵습니다.이는 다른 클래스(로드되지 않았을 수도 있음)에서 발생할 수 있기 때문입니다.그러나 JVM은 Jon이 설명한 기술을 사용할 수 있습니다(최적화, 필드가 변경되는 클래스가 로드되면 되돌리기).
요약하면 퍼포먼스에 도움이 될 이유가 없다고 생각합니다.따라서 이러한 미세 최적화는 도움이 되지 않습니다.만약을 위해 벤치마킹을 시도해 볼 수는 있지만, 차이가 있을지는 의문입니다.
편집:
사실, 티모 웨스트켐퍼의 대답에 따르면final
는 클래스 필드의 성능을 향상시킬 수 있습니다.난 잘못을 인정합니다.
주의: Java 전문가가 아닙니다.
자바가 제대로 기억되면 최종 키워드를 사용하여 성능을 향상시킬 수 있는 방법은 거의 없습니다.디자인이나 가독성이라고 하는 「좋은 코드」를 위해서 존재하는 것을 알고 있었습니다.
최종(적어도 멤버 변수와 파라미터의 경우)은 기계보다 인간에 더 적합합니다.
가능한 한 변수를 최종화하는 것이 좋습니다.Java가 기본적으로 "변수"를 최종화하고 변경을 허용하는 "변수" 키워드를 가지고 있었으면 합니다.불변의 클래스는 훨씬 더 나은 스레드 코드로 이어지며, 각 멤버 앞에 "최종"이 있는 클래스를 힐끗 쳐다보는 것만으로도 불변의 클래스임을 금방 알 수 있습니다.
또 다른 경우 - @NonNull/@Nullable 주석을 사용하기 위해 많은 코드를 변환하고 있습니다(메서드 파라미터는 null이 아니어야 하며 IDE는 @NonNull 태그가 없는 변수를 통과하는 모든 곳에 경고를 보낼 수 있습니다). 이 모든 것이 터무니없이 확산됩니다.멤버 변수 또는 파라미터는 다른 곳에서 재할당되지 않기 때문에 최종 태그가 부착된 경우 null일 수 없음을 증명하는 것이 훨씬 쉽습니다.
디폴트로는 멤버와 파라미터에 final을 적용하는 습관을 들이는 것이 좋습니다.몇 글자에 불과하지만 다른 것은 없다면 코딩 스타일을 개선하도록 유도할 것입니다.
메서드 또는 클래스의 최종은 매우 유효한 재사용을 허용하지 않고 독자에게 많은 것을 주지 않기 때문에 또 다른 개념입니다.String과 다른 본질적인 타입을 최종화한 것이 가장 좋은 용도일 것입니다.그러면 어디에서나 일관된 동작에 의존할 수 있기 때문에 많은 버그를 방지할 수 있습니다(스트링을 확장하고 싶을 때도 있지만).oh 가능성)
다른 곳에서 언급했듯이, 지역 변수에 대한 '최종'과 구성원 변수에 대한 '최종'은 스타일의 문제이다.
'최종'은 변수를 변경하지 않는다는 의미입니다(즉, 변수는 변하지 않습니다!).그 후 컴파일러는 사용자가 자신의 제약을 위반했을 경우 불만을 표시하여 도움을 줄 수 있습니다.
디폴트로는 식별자(죄송합니다만, 가변적이지 않은 것을 「변수」라고 부를 수 없습니다)가 최종적인 것이라면, Java가 더 좋은 언어가 되었을 것이라는 생각을 공유해, 그것들이 변수라고 명시적으로 말할 것을 요구했습니다.그러나 초기화되고 할당되지 않은 로컬 변수에는 일반적으로 "final"을 사용하지 않습니다. 너무 시끄럽습니다.
(멤버 변수에 final을 사용합니다)
제가 전문가는 아니지만, 제 생각에 당신이 덧붙여야 할 것 같아요.final
키워드를 클래스 또는 메서드에 지정합니다(덮어쓰기되지 않고 변수를 그대로 둡니다.이러한 작업을 최적화할 수 있는 방법이 있다면 컴파일러가 대신합니다.
실제로 OpenGL 관련 코드를 테스트하던 중 개인 필드에서 최종 수식자를 사용하면 성능이 저하될 수 있음을 발견했습니다.테스트한 수업의 시작은 다음과 같습니다.
public class ShaderInput {
private /* final */ float[] input;
private /* final */ int[] strides;
public ShaderInput()
{
this.input = new float[10];
this.strides = new int[] { 0, 4, 8 };
}
public ShaderInput x(int stride, float val)
{
input[strides[stride] + 0] = val;
return this;
}
// more stuff ...
사이는 ShaderInput 수업을 받을 때 다양한 대안의 성능을 확인하기 위해 이것이 메서드:.
public static void test4()
{
int arraySize = 10;
float[] fb = new float[arraySize];
for (int i = 0; i < arraySize; i++) {
fb[i] = random.nextFloat();
}
int times = 1000000000;
for (int i = 0; i < 10; ++i) {
floatVectorTest(times, fb);
arrayCopyTest(times, fb);
shaderInputTest(times, fb);
directFloatArrayTest(times, fb);
System.out.println();
System.gc();
}
}
후에 VM으로 3반복, 따뜻해졌다 일관성을 최종 키 말 없이:이 숫자들을 받았다.
Simple array copy took : 02.64
System.arrayCopy took : 03.20
ShaderInput took : 00.77
Unsafe float array took : 05.47
마지막 키워드로:
Simple array copy took : 02.66
System.arrayCopy took : 03.20
ShaderInput took : 02.59
Unsafe float array took : 06.24
그 ShaderInput 시험에 대한 수치를 기록한다.
나가 농장이나 개인의 중요하지 않았다.
그런데, 여기에는 몇가지 더 당혹케 하는 일이 있다.그 ShaderInput 클래스, 마지막 키워드에도 불구하고 다른 모든 변이를 압도한다.기본적으로 클래스 떠 있는 배열 포장하고 이것은 놀라운 b/c, 반면 다른 시험 직접 배열을 조작하다이 일도 알아낼 생각은 없다.뭔가 ShaderInput의 유창한 인터페이스와 관련 말씀 드리겠습니다.
또한 시스템.ArrayCopy 실제로 분명히 다소 작은 배열에 단순히 다른 의 루프에 배열에서 나온 요소를 복사하는 것보다 느리다.그리고 sun.misc을 사용하여.(직접 java.nio 위험한.FloatBuffer, 여기서 보여 드리지 않)혹독하게 수행한다.
final
Keyword 다섯가지 방법으로 자바에 사용될 수 있다.
- A학급은 기말고사입니다.
- 참조 변수가 최종 변수입니다.
- 로컬 변수는 최종 변수입니다.
- 방법은 최종입니다.
클래스는 최종 클래스입니다.클래스는 최종 클래스입니다.확장이 불가능하거나 상속이 불가능함을 의미합니다.
마찬가지로 오브젝트는 최종입니다.이 경우 오브젝트의 내부 상태를 변경하지 않기 때문에 오브젝트가 최종 오브젝트임을 지정할 수 있습니다.object final은 변수 없음도 final입니다.
참조 변수가 최종 설정되면 다른 객체에 재할당할 수 없습니다.그러나 필드가 최종 필드가 아닌 한 개체의 내용을 변경할 수 있습니다.
언급URL : https://stackoverflow.com/questions/4279420/does-use-of-final-keyword-in-java-improve-the-performance
'programing' 카테고리의 다른 글
Objective-C에서 ENUM을 정의하고 사용하려면 어떻게 해야 합니까? (0) | 2022.07.11 |
---|---|
C에 휘발성이 필요한 이유는 무엇입니까? (0) | 2022.07.11 |
Vue.js - Javascript Dynamic Imports를 사용하여 다른 서버에서 컴포넌트를 로드할 수 있습니까? (0) | 2022.07.11 |
Vuex 프로파일링 : 메모리 내의 vuex 상태 또는 컴포넌트 크기를 확인하는 방법 (0) | 2022.07.11 |
vue 맵 상태를 사용하여 어레이를 v-modeling합니다. (0) | 2022.07.11 |