source

Java 8 컨스트럭터 레퍼런스의 경이로운 퍼포먼스와 큰 히프 풋프린트

manycodes 2022. 12. 5. 21:31
반응형

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[]할당될 수 있습니다.OutOfMemoryErrors.

다음은 두 컨스트럭터의 현재 구현입니다.

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

반응형