Objects.requireNonNull은 이전 방식보다 덜 효율적입니까?
JDK 7 이후 null
로는 받아 들일 수없는 메서드에 전달 된 값 을 거부하기 위해 도입 한 메서드를 사용하고 있습니다.
private void someMethod(SomeType pointer, SomeType anotherPointer) {
Objects.requireNonNull(pointer, "pointer cannot be null!");
Objects.requireNonNull(anotherPointer, "anotherPointer cannot be null!");
// Rest of method
}
나는이 방법이 읽기 쉬운 매우 깔끔한 코드를 만든다고 생각하고 동료들이 사용하도록 장려하고있다. 그러나 한 (특히 지식이 풍부한) 동료는 저항하며 예전 방식이 더 효율적이라고 말합니다.
private void someMethod(SomeType pointer, SomeType anotherPointer) {
if (pointer == null) {
throw new NullPointerException("pointer cannot be null!");
}
if (anotherPointer == null) {
throw new NullPointerException("anotherPointer cannot be null!");
}
// Rest of method
}
그는 호출 requireNonNull
이 JVM 호출 스택에 다른 메소드를 배치 하는 것을 포함하며 단순한 == null
검사 보다 성능이 저하 될 것이라고 말합니다 .
그래서 내 질문 : 방법 을 사용하여 성능 저하가 발생 했다는 증거 가 Objects.requireNonNull
있습니까?
requireNonNull
Oracle JDK 의 구현을 살펴 보겠습니다 .
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
그래서 그것은 매우 간단 합니다. JVM (어쨌든 Oracle)에는 바이트 코드를 기계 코드로 변환하는 최적화 된 2 단계 Just-in-Time 컴파일러가 포함되어 있습니다. 더 나은 성능을 얻을 수 있다면 이와 같은 사소한 방법을 인라인합니다.
따라서 더 느리거나 의미있는 방식으로도, 중요하지 않을 가능성이 있습니다.
그래서 내 질문 : 방법 을 사용하여 성능 저하가 발생 했다는 증거 가
Objects.requireNonNull
있습니까?
중요 할 유일한 증거의 성능 측정 될 것이다 당신의 코드베이스, 또는 코드의 그것의 높은 대표 할 수 있도록 설계. 당신은 할 수 있습니다 , 나는 당신을 생각하는 경향이 것 어떤 점잖은 성능 테스트 도구를 사용하여이를 테스트,하지만 동료가 (오히려 합성 벤치 마크에 비해)이 방법에 관한 당신의 코드베이스에서 성능 문제의 실제 예제를 가리킬 수 있습니다하지 않는 한 그는 더 큰 물고기를 튀길 수 있습니다.
약간 제쳐두고 샘플 방법이 방법이라는 것을 알았습니다 private
. 따라서 팀이 작성하는 코드 만 직접 호출합니다. 이러한 상황에서 런타임 검사가 아닌 어설 션에 대한 사용 사례가 있는지 확인할 수 있습니다 . 어설 션은 "출시 된"코드에서 전혀 실행되지 않는 이점이 있으므로 질문의 두 대안보다 빠릅니다. 분명히 런타임 검사가 필요한 곳이 있지만 일반적으로 게이트 키핑 지점, 공용 메서드 등에 있습니다. 그냥 FWIW.
공식적으로 말하면 동료가 옳습니다.
경우
someMethod()
추적을 대응하는 뜨거운 충분하지 않거나, 바이트 코드를 해석하고, 여분의 스택 프레임이 만들어집니다경우
someMethod()
뜨거운 지점에서 깊이의 9 번째 수준에서 호출되면requireNonNull()
호출 때문에의 인라인해서는 안MaxInlineLevel
JVM 옵션위의 이유로 메소드가 인라인되지 않은 경우 오류 메시지를 생성하기 위해 연결을 사용하면 TJ Crowder의 인수가 작동합니다.
requireNonNull()
인라인 된 경우에도 JVM은이를 수행하는 데 시간과 공간을 낭비합니다.
반면에 FreqInlineSize
너무 큰 (바이트 코드) 메서드를 인라인하는 것을 금지하는 JVM 옵션이 있습니다. 메서드의 바이트 코드는이 메서드 내에서 호출되는 메서드의 크기를 계산하지 않고 자체적으로 계산됩니다. 따라서 코드 조각을 독립적 인 메서드로 추출하는 것이 때때로 유용 할 수 있습니다. requireNonNull()
이 추출을 사용한 예제에서는 이미 만들어졌습니다.
증거 를 원하면 ... 그것을 얻는 방법은 마이크로 벤치 마크를 작성하는 것입니다.
(저는 먼저 Calliper 프로젝트를 살펴볼 것을 권장합니다! 또는 Boris의 권장 사항에 따라 JMH ... 어느 쪽이든, 처음부터 마이크로 벤치 마크를 작성하려고 시도하지 마십시오. 잘못된 방법이 너무 많습니다.)
그러나 동료에게 다음 두 가지를 말할 수 있습니다.
JIT 컴파일러는 작은 메서드 호출을 인라인하는 작업을 잘 수행하며이 경우에 이런 일이 발생할 가능성이 높습니다.
호출을 인라인하지 않은 경우 성능 차이가 3 ~ 5 개 명령에 불과할 가능성이 높으며 큰 차이를 만들 가능성은 거의 없습니다.
예, 수동 null
확인과 Objects.requireNonNull()
무시할 수 있는 차이가 있다는 증거가 있습니다. OpenJDK 커미터 Aleksey Shipilev 는 JDK-8073479 를 수정하면서이를 증명하는 벤치마킹 코드 를 만들었습니다. 그의 결론과 성능 수치는 다음과 같습니다.
TL;DR: Fear not, my little friends, use Objects.requireNonNull.
Stop using these obfuscating Object.getClass() checks,
those rely on non-related intrinsic performance, potentially
not available everywhere.
Runs are done on i5-4210U, 1.7 GHz, Linux x86_64, JDK 8u40 EA.
The explanations are derived from studying the generated code
("-prof perfasm" is your friend here), the disassembly is skipped
for brevity.
Out of box, C2 compiled:
Benchmark Mode Cnt Score Error Units
NullChecks.branch avgt 25 0.588 ± 0.015 ns/op
NullChecks.objectGetClass avgt 25 0.594 ± 0.009 ns/op
NullChecks.objectsNonNull avgt 25 0.598 ± 0.014 ns/op
Object.getClass() is intrinsified.
Objects.requireNonNull is perfectly inlined.
어디에서 branch
, objectGetClass
그리고 objectsNonNull
다음과 같이 정의된다 :
@Benchmark
public void objectGetClass() {
o.getClass();
}
@Benchmark
public void objectsNonNull() {
Objects.requireNonNull(o);
}
@Benchmark
public void branch() {
if (o == null) {
throw new NullPointerException();
}
}
동료가 틀렸을 가능성이 큽니다.
JVM은 매우 지능적이며 Objects.requireNonNull(...)
메소드를 인라인 할 가능성이 높습니다 . 성능은 의심 스럽지만 이것보다 훨씬 더 심각한 최적화가있을 것입니다.
JDK의 유틸리티 메소드를 사용해야합니다.
Joshua Bloch의 효과적인 자바
아이템 67 : 신중하게 최적화하라
모두가 알아야 할 최적화에 관한 세 가지 격언이 있습니다.
More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason—including blind stupidity.
—William A. Wulf [Wulf72]We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
—Donald E. Knuth [Knuth74]We follow two rules in the matter of optimization:
Rule 1. Don’t do it.
Rule 2 (for experts only). Don’t do it yet—that is, not until you have a perfectly clear and unoptimized solution.
—M. A. Jackson [Jackson75]
As a general rule, readability and maintainability should trump optimization.
This rule safeguards against speculative optimization from people who think they know how a compiler works even though they have never even attempted to write one and they have never had a look inside one.
Your colleague is wrong unless they prove that the performance penalty is noticeable and untenable for users.
Objects.requireNonNull is more optimised as if you this you are code reusability. Also in oracle requireNonNull si defined as
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
so its already in bytecode.
'IT TIP' 카테고리의 다른 글
HTML 닫기 (0) | 2020.12.04 |
---|---|
Visio 2013에서 UML 다이어그램 셰이프 누락 (0) | 2020.12.04 |
PHP7.1 json_encode () 플로트 문제 (0) | 2020.12.04 |
Ruby에서 언제`require`,`load` 또는`autoload`를 사용합니까? (0) | 2020.12.04 |
HTTP 응답을 보낸 후 계속 PHP 실행 (0) | 2020.12.04 |