플라이 웨이트 (Flyweight) 패턴이란?
- 구조와 관련된 디자인 패턴이다.
- 변화하지 않는(intrinsic) 재사용 가능한(resuable) 커다란 객체를 캐시에 저장해두고 재활용하는 기법이다.
- 여러 개의 클래스 내부 필드 중 공통으로 사용되는 필드를 따로 빼내어 공유하여 메모리를 더 확보할 수 있게 해준다.
flyweight
의 영단어 뜻은 스포츠에서 아주 가벼운 체급을 말한다.- 필드의 중복을 최적화할 수 있어서 많은 인스턴스를 만드는 애플리케이션에서 효율이 좋다.
- OOM 현상을 방지하는데 유용하다.
- 자주 변경되는 속성 (Intrinsic State) 과 자주 변경되지 않는 속성 (Extrinsic State) 을 분리하여 자주 변경되지 않는 것을 재사용한다.
- 객체지향적 디자인이 목적이라기보다 성능 향상에 주된 목적이 있다.
다이어그램으로 보기
게임의 예
- 게임에서 메모리 최적화를 이뤄내는 예를 통해 flyweight 패턴을 배워볼 수 있다.
문제
- 게임에서 몬스터를 대량으로 나타나게 하려는 순간 게임이 OOM 과 함께 크래시되는 현상이 일어난다.
- 몬스터를 생성하는데 너무 많은 메모리 자원이 소비된다고 예측할 수 있다.
Monster
클래스의 메모리 분석
- 위는 몬스터 클래스를 다이어그램으로 표현해본 것이다.
- 몬스터 하나당 메모리 비용 계산해보기
coords
:8B
vector
:16B
speed
:4B
color
:4B
sprite
:20KB
- 몬스터 한마리에 약
21KB
의 용량이 소비되며, 1,000,000 마리 기준으로21GB
의 메모리가 소비된다. - 특히
sprite
는20KB
로 다른 필드보다 훨씬 많은 메모리를 소비한다.
필드가 가지는 특성 구분하기
- 필드를
intrinsic state
와extrinsic state
로 구분할 수 있다. intrinsic state
- 오브젝트에서 공유 가능하며 변하지 않는 (immutable) 프로퍼티를 말한다.
- 여러 인스턴스에서 공유해도 큰 문제가 되지 않고 독립적인 프로퍼티이다.
- 내재 상태인
intrinsic state
만 저장하는 오브젝트를 flyweight 오브젝트라고 한다. - flyweight 패턴에선 flyweight 오브젝트 자체에 의해 관리된다.
- 내부에 존재하는 값이라는 뜻을 가지고 있다.
extrinsic state
- 각 오브젝트에서 가져야 하는 고유한 (unique) 값이다.
- 공유되면 안되며, flyweight 오브젝트를 사용하는 클라이언트 코드에서 관리되어야 한다.
- 외부로부터 생성되는 값이라는 뜻을 가지고 있다.
intrinsic state
를 구분한다면?
- 기존의
20KB + 32B
메모리를 차지하지 않고32B
만 남게 된다. - 100만개를 생성해도 32MB 의 메모리만 차지하게 된다.
MonsterFactory
구현하기
MonsterFactory
를 이용해Monster
객체를 생성하도록 전략을 바꿨다.- 모든
Monster
생성은MonsterFactory
를 통해 이루어진다. Monster
의 생성자는 막아버린다.
- 모든
MonsterFactory
는Monster
생성 시sprite
객체 생성에 대한 전략을 갖는다.- 몬스터의
sprite
정보가spriteCache
에 있는지 확인하고 없다면, 새로 생성한다. sprite
정보가spriteCache
에 존재한다면, 새로 생성하지 않고 이미 만들었던 객체를 같이 쓴다.
- 몬스터의
나중에 다시 무거운
intrinsic state
가 등장한다면?MonsterFactory
에 해당 캐시를 하나 더 추가해주면 된다.
자바에 적용된 Flyweight 패턴인 스트링 풀 살펴보기
- 자바의 스트링 풀 은 Flyweight Pattern 의 좋은 예이다.
- 테스트코드를 통해 각기 다른 변수에 같은 문자열을 넣었을 때 가리키는 주소가 같다는 사실을 쉽게 알 수 있다.
System.identityHashCode()
메서드는 오브젝트가 가리키는 객체의 주소 반환하는 메서드이다.- 아래 코드에서
myName1
과myName2
는 같은 문자열을 가리킨다.
class StringTest {
@Test
public void stringAddressTest() {
String myName1 = "Jake Seo";
String myName2 = "Jake Seo";
System.out.println("myName1 = " + System.identityHashCode(myName1)); // 793331940
System.out.println("myName2 = " + System.identityHashCode(myName2)); // 793331940
}
}
같은 주소를 가리키는 이유
- 자바는 한번 새로운 문자열을 사용하면 해당 문자열을 '스트링 풀' 이라는 곳에 캐싱한다.
- 단, 내부 정책에 따라서 수행하므로 너무 길거나 일반적이지 않은 문자라면 캐싱하지 않을 수도 있다.
- 다음에 새로운 문자열이 들어오면 무작정 문자열 객체를 만드는 것이 아니라 '스트링 풀' 에서 해당 문자를 가져와 사용하게 된다.
- 자바 입장에서
String
타입은 불변이어서intrinsic state
로 바라보게 되기 때문이다.
Flyweight 패턴을 사용할 때 주의점
intrinsic state
를 다루는 객체는 반드시instrinsic state
를 immutable 하게final
로서 다뤄야 한다.- 다들 공유하는 상태이기 때문에 바뀌어선 안된다.
Flyweight 패턴의 장점과 단점
장점
- 애플리케이션이 사용하는 메모리를 줄일 수 있다.
단점
- 애플리케이션의 복잡도가 살짝 올라간다.
- 캐싱에 대한 이해가 있어야 코드 파악이 된다.
레퍼런스
반응형
'Java > 자바 디자인 패턴' 카테고리의 다른 글
책임 연쇄 패턴 (Chain Of Responsibility) 이란? (2) | 2023.04.26 |
---|---|
프록시 패턴 (Proxy Pattern) 이란? (0) | 2023.04.25 |
퍼사드 패턴 (Facade Pattern) 이란? (0) | 2023.04.18 |
데코레이터 패턴 (Decorator Pattern) 이란? (0) | 2023.02.25 |
컴포지트 패턴 (Composite Pattern, 컴포짓 패턴) 이란? (0) | 2023.02.20 |