5. 어노테이션과 MetaSpace, 배열 병렬 정렬

Java8에 변경된 사항중 어노테이션과, MetaSpace, 배열 정렬 알고리즘에 대해 정리한 글

애노테이션의 변화

1. 애노테이션 관련 두가지 큰 변화

  • 자바 8부터 애노테이션을 타입 선언부에도 사용할 수 있게 됨

  • 자바 8부터 애노테이션을 중복해서 사용할 수 있게 됨

1-1. 타입 선언 부

  • 제네릭 타입

  • 변수 타입

  • 매개변수 타입

    • @Target(ElementType.TYPE_PARAMETER)

  • 예외 타입

  • etc

1-1-1. 기존의 애노이션 Target 종류

  • TYPE : 클래스 / 인터페이스 / 어노테이션 / enum / record의 선언부

  • ANNOTATION_TYPE : 어노테이션의 선언부

  • FIELD : 클래스내의 내부필드의 선언부

  • METHOD : 클래스내의 메서드의 선언부

  • PARAMETER : 메서드내의 파리미터의 선언부

  • CONSTRUCT : 생성자의 선언부

  • LOCAL_VARIABLE : 지역변수의 선언부

  • PACKAGE : 해당 패키지의 package-info.java 에 붙일 수 있다.

1-1-2. java8에 추가된 Target

타입에 애노테이션을 사용하기 위해 아래와 같은 ENUM 타입을 명시해야 함.

  • TYPE_PARAMETER : 타입 변수에만 사용할 수 있다.

  • TYPE_USE : 타입 변수를 포함해서 모든 타입 선언부에 사용할 수 있다.

  • 위의 어노테이션들과는 다르게 선언 주석이 아닌 TYPE 주석이다.

    • 선언 주석 : 주의사항, 사용방법, 사용처 등 설명

    • TYPE 주석 : 정수 값이 0보다 커야 한다, null이 아니다 와 같은 값에 대한 정보 제공함으로써 implements, throws, new 구절에 사용하거나 제네릭에 사용함으로써 외부의 프로젝트에도 적용할 수 있도록 확장한 범위

TYPE_PARAMETERTYPE_USE에 대해 더 자세히 알아보기 위해 다음 예제를 살펴보자.

TYPE_PARAMETER

타입 선언부에 사용이 가능

컴파일하면서 해당 타입이 무슨 타입인지 분석하여 CLASS_TYPE_PARAMETER / METHOD_TYPE_PARAMETER 로 변환하는 것을 볼 수 있다.

타입 선언부에 사용이 가능한 Target이므로 아래와 같이 실제 사용하는 부분에는 적용할 수 없다.

TYPE_USE

선언부 뿐만이 아닌 타입 사용되는 모든 곳에 적용이 가능 (클래스/인터페이스/내부필드/파라미터/제네릭/지역변수 등)

바이트 코드를 보면 TYPE_USE를 사용해도 컴파일 결과는 컴파일러가 적절한 어노테이션 TARGET으로 바꾸는 것을 볼 수 있다.

Lombok의 NonNull 어노테이션으로 해당 어노테이션도 Target범위가 TYPE_USE가 포함되어 있다.

1-2. 중복 사용할 수 있는 애노테이션을 만들기

  • 중복 사용할 애노테이션 만들기

  • 중복 애노테이션 컨테이너 만들기

    • 컨테이너 애노테이션은 중복 애노테이션과 @Retention@Target이 같거나 더 넓어야 한다.

1-2-1. 중복 사용할 애노테이션 생성

기존에는 애노테이션을 같은 범위에 중복해서 정의할 수 없었는데 java8 부터는 @Repeatable()이 추가되어 중복해서 사용이 가능해졌다.

Repeatable은 한개의 value를 가지고 있는데, 여기에 일종의 애노테이션 컨테이너 역할을 할 애노테이션 클래스를 넘겨주면 해당 컨테이너에 중복 사용한 애노테이션들을 담는 방식으로 동작하게 된다.

이때 주의할 점이 Repeatable의 value는 애노테이션의 컨테이너 역할이기 때문에 중복해서 사용할 어노테이션보다 생명주기(RetentionPolicy)가 길어야만 한다.

1-2-2. 중복 애노테이션의 컨테이너 생성

1-2-3. 컨테이너 애노테이션으로 중복 애노테이션 참조

@Chicken 은 default value가 없으면 에러가 발생한다.

더 나아가서 main에서 2번째로 방법으로 컨테이너 애노테이션 타입으로 읽어들일 때 바이트 코드를 살펴보자.

ChickenContainer 애노테이션을 생성하여 Chicken 애노테이션들을 value로 할당하는 것을 볼 수 있다.

MethodHandles$Lookup라는 이름의 클래스로 innerClass가 만들어지는 것을 볼 수 있는데 이는 메서드 핸들을 생성하기 위한 factory class로 ChickenContainer의 value()인 Chicken[]에 접근하기 위한 class 이다.

배열 병렬 정렬

Arrays.parallelSort()가 추가되어 분산되어 정렬이 가능하다.

1. Arrays.parallelSort()

  • Fork/Join 프레임워크를 사용해서 배열을 병렬로 정렬하는 기능을 제공한다.

2. 병렬 정렬 알고리즘

  • 배열을 둘로 계속 쪼갠다.

  • 합치면서 정렬한다.

3. sort()와 parallelSort() 비교

  • 알고리즘 효츌성은 같다.

    • 시간복잡도 : O(n logN)

    • 공간복잡도 : O(n)

단, 정렬하는 배열의 크기에따라 속도가 차이날 수 있다.

참고

size가 15000일 때 나오는 속도

Arrays.sort()

  • Arrays.sort() 알고리즘은 기본적으로 DualPivotQuicksort를 사용한다.

이 알고리즘은 기본적으로

  1. Insertion Sort

  2. Merge Sort

  3. Quick Sort

위 3개의 알고리즘을 사용하는데 보통 1,2, 1,3을 섞어서 사용한다.

Arrays.parallelSort()

  • 반면 Arrays.parallelSort() 는 Merge Sort를 사용함.

img

Meta space

JVM의 여러 메모리 영역 중에 PermGen 메모리 영역이 없어지고 Metaspace 영역이 생겼다.

1. PermGen

  • 메모리 구조

    memory

🔼출처

  • permanent generation, 클래스 메타데이터를 담는 곳.

  • Heap 영역에 속함.

  • 기본값으로 제한된 크기를 가지고 있음.

    • 동적으로 클래스를 생성하는 경우 PermGen 영역이 가득 차는 경우가 발생할 수 있다. 메모리 에러 발생.

    • 위의 문제를 근본적으로 해결하려면 PermGen 사이즈를 늘리는 것이아니라 클래스를 동적으로 생성하는 코드를 수정해야한다.

  • XX:PermSize=N, PermGen 초기 사이즈 설정

  • XX:MaxPermSize=N, PermGen 최대 사이즈 설정

Old/Eden 영역보다 적은 메모리사이즈를 가지고 있으며 os bit, jdk 버전별로 다르다. 고정된 크기를 가지기 때문에 클래스를 계속해서 만들게 되면 GC가 메모리를 정리해도 PermGen사이즈를 넘어서면 memory out 에러가 발생한다.

2. Metaspace

  • 메모리 구조

    memory2

🔼출처

  • 클래스 메타데이터를 담는 곳.

  • Heap 영역이 아니라, Native 메모리 영역이다.

  • 기본값으로 제한된 크기를 가지고 있지 않다.

    • Native 메모리 영역이 가득찰 때까지 필요한 만큼 계속 늘어난다.

    • Native 메모리 영역이 가득차게 되면 서버가 죽는 치명적인 문제가 발생할 수 있다.

    • 따라서 최소한 Metaspace의 최대 사이즈는 설정해주어야한다.

    • 효율적으로 사용하려면 모니터링 하여 최적의 Metaspace 값을 찾아 최대값으로 설정하는 것이다. 만약 모니터링으로 도출해낸 이 값에 메모리 문제가 생기면 어딘가의 메모리 누수를 의심해보아야 한다.

  • 자바 8부터는 PermGen 관련 java 옵션은 무시한다.

  • XX:MetaspaceSize=N, Metaspace 초기 사이즈 설정.

  • XX:MaxMetaspaceSize=N, Metaspace 최대 사이즈 설정.

memory-management

Ref.

Last updated