Java 8 컨스트럭터 레퍼런스의 경이로운 퍼포먼스와 큰 히프 풋프린트
나는 단지 우리의 생산 환경에서 다소 불쾌한 경험을 했을 뿐이다.OutOfMemoryErrors: heapspace..
나는 그 문제를 추적했다.ArrayList::new
함수에서.
선언된 컨스트럭터를 통해 실제로 정상적으로 작성되지 않은 것을 확인한다(t -> new ArrayList<>()
)는 다음과 같은 작은 방법을 썼습니다.
public class TestMain {
public static void main(String[] args) {
boolean newMethod = false;
Map<Integer,List<Integer>> map = new HashMap<>();
int index = 0;
while(true){
if (newMethod) {
map.computeIfAbsent(index, ArrayList::new).add(index);
} else {
map.computeIfAbsent(index, i->new ArrayList<>()).add(index);
}
if (index++ % 100 == 0) {
System.out.println("Reached index "+index);
}
}
}
}
메서드 실행newMethod=true;
에 실패하는 원인이 됩니다.OutOfMemoryError
지수가 30,000에 도달한 직후입니다.와 함께newMethod=false;
프로그램은 실패하지 않고 죽을 때까지 계속 두들겨댄다(지수가 150만까지 쉽게 도달한다).
왜?ArrayList::new
많은 것을 만들어 내다Object[]
원인이 되는 힙상의 요소OutOfMemoryError
그렇게 빨리요?
(그런데 - 수집 유형이 다음과 같은 경우에도 발생합니다.HashSet
.)
첫 번째 경우(ArrayList::new
)는 첫 번째 capacity 인수를 사용하는 컨스트럭터를 사용하고 있습니다.두 번째 경우는 사용하지 않습니다.대규모 초기 용량(index
코드로)가 큰 원인이 됩니다.Object[]
할당될 수 있습니다.OutOfMemoryError
s.
다음은 두 컨스트럭터의 현재 구현입니다.
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
에서 비슷한 일이 일어나다HashSet
단, 어레이는 다음 시간까지 할당되지 않습니다.add
호출됩니다.
그computeIfAbsent
시그니처는 다음과 같습니다.
V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
그래서...mappingFunction
하나의 인수를 수신하는 함수입니다.고객님의 경우K = Integer
그리고.V = List<Integer>
따라서 시그니처는 (PECS 제외)가 됩니다.
Function<Integer, List<Integer>> mappingFunction
글을 쓸 때ArrayList::new
가 있는 곳에Function<Integer, List<Integer>>
컴파일러는 다음과 같은 적절한 컨스트럭터를 찾습니다.
public ArrayList(int initialCapacity)
즉, 기본적으로 당신의 코드는
map.computeIfAbsent(index, i->new ArrayList<>(i)).add(index);
그리고 당신의 열쇠는 다음과 같이 취급됩니다.initialCapacity
그 결과, 크기가 계속 증가하는 어레이가 사전 평가됩니다.물론, 이 값은 매우 빠르게 실현됩니다.OutOfMemoryError
.
이 경우 생성자 참조는 적합하지 않습니다.대신 람다를 사용하세요.그 때?Supplier<? extends V>
에 사용되다computeIfAbsent
,그리고나서ArrayList::new
적절할 것 같습니다.
언급URL : https://stackoverflow.com/questions/35296734/horrendous-performance-large-heap-footprint-of-java-8-constructor-reference
'source' 카테고리의 다른 글
메모리 효율이 뛰어난 SqlAlchemy Iterator/Generator 내장 (0) | 2022.12.05 |
---|---|
ReactJ는 HTML 문자열을 JSX로 변환합니다. (0) | 2022.12.05 |
IN 절을 사용한 업데이트의 경우 잠금 대기 시간 초과가 발생합니다. (0) | 2022.12.05 |
vue .net 코어 애플리케이션의 Vuex (0) | 2022.12.05 |
설치된 Python 버전은 무엇입니까? (0) | 2022.12.05 |