[F-Lab 챌린지 51일차 TIL]

성수데브리·2023년 8월 17일
0

f-lab_java

목록 보기
41/73

용어정의


불변객체?

생성 후 그 상태를 바꿀 수 없는 객체

대표적 예시

java.lang 패키지의 Integer, Boolean 등등 래퍼클래스

불변객체 장단점


장점

  1. GC 성능 높일 수 있다.

    불변 객체의 필드는 불변객체의 생명 주기와 함께한다. GC 스캔 대상에서 제외되기 때문에 GC 시 효율적으로 제거된다.

    반재로 가변 객체 참조를 소유하고 있으면 해당 참조값을 계속 추적해야한다.

    class ImmutableCart<T> {
    
      private final List<T> items;
    
      public ImmutableCart(List<T> items) {
        this.items = Arrays.asList(items.toArray());
      }
    
      public List<T> getItems() {
    
        return Collections.unmodifiableList(items);
      }
      public int total() { /* return sum of the prices */ }
    }
  2. 불변객체는 객체 복사 시 가변객체와 달리 얕은 복사만 하면 된다.

  3. 멀티 스레드 환경에서 안전성

    복수의 스레드에 의해서 특정한 스레드의 데이터가 변경될 우려없이 데이터에 접근할 수 있다. 즉, 배타 제어(mutual exclusion)를 할 필요가 없다. 쉽게 말해 불변 객체가 가변 객체보다 스레드 세이프(Thread-safe) 하다고 생각하면 된다.

  4. Cache, Map, Set 등의 요소로 활용하기에 적합

    불변객체를 Cache, Map, Set 한 번 할당하면 다시 쓰기작업이 필요 없으므로 좋다.

단점

  1. 객체가 변경 가능한 데이터를 많이 가지고 있는 경우엔 불변이 오히려 부적절한 경우가 있다.

불변객체 만들기


1. 불변객체 구현

class ImmutableCart<T> {
	// 2 필드의 접근 제어자 private, 3 final 선언
  private final List<T> items;

  public ImmutableCart(List<T> items) {
    this.items = Arrays.asList(items.toArray());
  }

	// 1 수정자 메서드 만들지 않기

  public List<T> getItems() {
		// 4 수정 불가한 콜렉션으로 변경
    return Collections.unmodifiableList(items);
  }
  public int total() { /* return sum of the prices */ }
}
  1. 수정자 메서드 만들지 않기

  2. 필드의 접근 제어자 private

    1. 외부에서 필드에 직접 접근하여 수정 차단한다.
  3. 상속 시 서브클래스에서 변경 가능성 차단

    1. final 선언하여 서브 클래스에서 필드 값 수정 가능성 차단한다.
    2. final 선언하여 메서드 overriding 불가하게 만든다.
  4. 콜렉션 타입으로 래핑된 필드일 경우

    콜렉션이 래핑하고 있는 원소 객체를 수정할 가능성이 있으니 getter 메서드에서 수정 불가한 콜렉션으로 변경해준다.

2. 가변객체는 불변 객체처럼

카피 온 라이트(Copy-On-Write)다.
이 기법에서는 이용자가 시스템에 객체를 복제하도록 명하면 복사 대신 동일한 객체를 가리키는 참조를 만든다. 그리고 이용자가 그 참조를 통해 객체를 변경하면 그때 진짜 복제를 만들고 그것을 가리키는 참조를 다시 생성한다.
이에 의해 다른 이용자는 영향을 받지 않는다. 왜냐하면 여전히 원본 객체를 참조하고 있기 때문이다.
카피 온 라이트 환경에서 모든 이용자는 가변 객체를 갖고 있는 것처럼 보이지만 그 객체를 변경하지 않는한 불변 객체로서 실행 효율을 높일 수 있다.
카피 온 라이트는 가상 기억 시스템에서 자주 사용되며 프로그램이 다른 프로그램에 메모리를 수정할 걱정없이 메모리를 절약할 수 있다.

  • 불변객체 필드에 가변객체가 있다면 객체의 참조값을 넘겨줄 때 방어적 복사를 하여 새로 생성한 객체 참조값을 넘긴다.

JVM 의 Memory Model

  • JVM 내 메모리 영역은 크게 Heap, Non-Heap, Cache 로 구분한다.
  • 자세히 구분하면 아래와 같다.
    1. PC 레지스터
    2. JVM 스택
    3. heap ———→ GC 가 발생하는 영역
    4. 메서드 영역
    5. 런타임 상수 풀
    6. 네이티브 메서드 스택

1. Heap Memory

참고

-Xms초기 heap 크기
-Xmx최대 heap 크기
-XX:NewSizeYoung Generation 영역의 최초 크기
-XX:MaxNewSizeYoung Generation 영역의 최대 크기를 제한
-XX:MaxPermGenPerm 영역의 최대크기
-XX:SurvivorRatioYoung Generation 내의 Survivor 영역의 비율을 조절하는 매개변수.

예를 들어 "SurvivorRatio=3"이라면 Eden 영역 크기에 비해 각 Survivor 영역의 크기가 1:3 비율로 설정된다는 뜻 |

  • Heap 은 두 부분으로 나뉜다. - Young GenerationOld Generation
  • Heap 크기는 어플리케이션 동작중에 변경될 수 있다.

Young Generation

  • 영 제너레이션 영역에는 새로 생성된 객체들이 할당되는 공간이다.
  • 영 제너레이션은 다시 세 영역으로 나뉘는데, Eden, 두 개의 Survivor 영역으로 나뉜다. (S0, S1)
  • Eden 영역이 꽉차면 Minor GC 가 발동하는데, Eden 영역의 객체를 Survivor 영역 중 빈 곳으로 옮긴다.

Old Generation

  • 여러 차례의 Minor GC 에도 살아남은 객체들이 특정 임계치를 넘어서면 옮겨지는 영역이다.
  • 올드 제너레이션 영역이 꽉차면 Major GC 가 작동한다.

2. Non-Heap Memory

  • Permanent Generation 이라고 하는 영역이 존재한다. (Java8 이후부터 Metaspace 라 한다)
  • GC 관리 영역이 아니다.
  • 클래스마다 아래 데이터를 갖는다.
    • runtime constant pool
    • field
    • method data
    • code for method and constructors

3. Cache Memory

  • Code Cache 영역이 있다.
  • JIT 컴파일러의 컴파일된 코드가 저장된다.
  • profiler agent 의 코드와 데이터가 저장된다.
  • 이 영역의 할당 용량이 특정 임계치를 넘어서면 비워지는데 GC 가 수행하는 것은 아니다.

1개의 댓글

comment-user-thumbnail
2023년 8월 17일

많은 도움이 되었습니다, 감사합니다.

답글 달기