기타/리펙토링

Static EnumMap 의 초기화 위치별 메모리 영향

oiNeh 2022. 6. 10. 23:22

어느 깊은 여름밤 잠에서 깨어난 개발자가 울고 있었다.

(무슨 꿈을 꾸 .. ) 

 

 

 

코드를 짜면서 메모리 에 걱정이 들기 시작했다 


 

(리펙토링 전) 내가 만든 코드 확인 

 

GitHub - kureung/good-price-good-product

Contribute to kureung/good-price-good-product development by creating an account on GitHub.

github.com


모든 유저가 동일한 Enum 필드 값을 가지고 있고

Enum 클래스 내 EnumMap 초기값을 가질려면 어떻게 만들어야 할까 고민을 하는 와중 

그래 그냥 생각나는 데로 다 만들어보자!

 

자 실험을 시작하지

[entity 생성 부분]

User usera = new User("T", Role.USER, T.init());

< 상속 받는 부분 > 

User<T extends ABC> 상속

A,B,C implements ABC 

1. enum static init() 만들고 entity객체 생성 시 넣어주기 (기존 방식)

 

    private static void A() {
        sequenceA.put(...);
        sequenceA.put(... );
    }
    
    public static A init() {
        A();
        return A.ACCEPT;
    }

    private static final EnumMap<A, A> sequenceA =
            new EnumMap<>(A.class);

 

2. enum EnumMap 초기화 값을 리턴 메소드로 넣어주기

     -1  Map to EnumMap 캐스팅 리턴

     

    public static B init() {
        return B.ACCEPT;
    }

    private static EnumMap<B, B> B() {
        return (EnumMap<B, B>)
                Map.of(...  );
    }

    private static final EnumMap<B, B> sequenceB = B();

        

     -2 EnumMap 객체 생성 후 리턴 

public static C init() {
    return C.ACCEPT;
}

private static EnumMap<C, C> C() {
    EnumMap<C, C> map = new EnumMap<>(C.class);

    map.put(...);
    map.put(...);

    return map;
}

private static final EnumMap<C, C> sequenceC =  C();

자 이제  코드들을 실행하면 어떤 결과가 나올까?

 

그전에 위 코드들을 조금 수정하면서 어떤 리턴 값이 나오는지 확인해보자

(A는 처음에 만들었던 코드라 패턴에 포함 x)

 

실험 조건은

실험하기 전 서로 객체 하나를 만들어 한 번씩 실행했다. 

반복 횟수 2147483647 회(Integer.MAX_VALUE)

측정 함수: System.nanoTime(); -> ((double) nanoTime) / 1000000000

[Pattern -1]

init(){ T(); } 

sequence = new EnumMap<>(T.class);
T(){//... 값 넣어주기}

B 결과 - ClassCastException -> map to EnumMap 캐스팅 에러

C 결과 - 실행시간 : 30초 , 리턴 값 null;

 

[Pattern -2]

sequence = new EnumMap<><T.class>;

 B 결과 - 실행시간 : 0.001초 , 리턴값 null;
 C 결과 - 실행시간 : 0.001초 , 리턴값 null;

 

패턴 2는 유일하게 이방식에서 리턴값?을 리턴해줘서 추가함

 

[Pattern -3]

 sequence = T();

 B 결과 - ClassCastException -> map to EnumMap 캐스팅 에러
 C 결과 - 실행시간 : 0.001초 , 리턴값 존재함

 

여기서 B는 사용할 수 없는 거라 판단이 들어

A와 B를 비교해 보았다.

 

A 테스트 코드

    public static void testA(int count) {

        long time = System.currentTimeMillis();

        reportPerformanceFor(" A before", time);
        for (int i = 0; i < count; i++) {
            User userA = new User("A", Role.USER, A.init());
            userA.next();
        }

        reportPerformanceFor(" A after", time);
    }

실행 결과 : 12.8665652초 ,  메모리 10.519MB 증가 

 

 

C 테스트 코드 

  public static void testB(int count) {

        long time = System.currentTimeMillis();

        reportPerformanceFor(" C before", time);
        for (int i = 0; i < count; i++) {
            User userC = new User("C", Role.USER, C.init());
            userC.next();

        }
        reportPerformanceFor(" C after", time);

    }

 


실행 결과: 0.0185339 초 , 메모리 -16.3604049683 MB 감소

 

시간 차이가 무려 700배 , 메모리 영역은 오히려 감소하는 기이한 형상이 일어났다. 

 

여기서 또 출력도 3가지 패턴이 있다. 

ㅋㅋㅋ

 

[출력문]

A 1번 호출 , C 1번 호출

----------------------------------------------------------------------------------------------------

 

 A before (nanoTime :366446.8587579 , 4.9620513916015625 MB) 
 A after   (nanoTime :366459.5092968 , 18.48230743408203 MB) 
 
 C before (nanoTime :366459.5094344 , 18.48230743408203 MB) 
 C after    (nanoTime :366459.527259  , 6.1203765869140625 MB) 

----------------------------------------------------------------------------------------------------

? 뭐지 


[출력문]

A 1번 호출 , C 6번 호출

----------------------------------------------------------------------------------------------------

 A before (nanoTime :362633.3446298 , 4.9621124267578125 MB) 
 A after    (nanoTime :362645.9432127 , 14.482307434082031 MB) 
 
 C before (nanoTime :362645.9433499 , 14.482307434082031 MB) 
 C after    (nanoTime :362645.955507   , 20.481971740722656 MB) 
 C before (nanoTime :362645.9555983 , 20.481971740722656 MB) 
 C after    (nanoTime :362645.9666415 , 3.6124649047851562 MB) 
 C before (nanoTime :362645.9667442 , 3.6124649047851562 MB) 
 C after    (nanoTime :362645.9667968 , 3.6124649047851562 MB) 
 C before (nanoTime :362645.9668351 , 3.6124649047851562 MB) 
 C after    (nanoTime :362645.9669407 , 3.6124649047851562 MB) 
 C before (nanoTime :362645.966973   , 3.6124649047851562 MB) 
 C after    (nanoTime :362645.9670724 , 3.6124649047851562 MB) 
 C before (nanoTime :362645.9671015 , 3.6124649047851562 MB) 
 C after    (nanoTime :362645.9671953 , 3.6124649047851562 MB) 

----------------------------------------------------------------------------------------------------

그래도 그렇지 메모리가 감소가 되나 어... 이게 바로 가비지 컬렉션? (할당 값 주소 재활용 같은 건가?)

 


[출력문]

 C 4번 호출

----------------------------------------------------------------------------------------------------

C before (nanoTime :362148.9913814 , 4.9620513916015625 MB) 
C After    (nanoTime :362149.0033177 , 9.961990356445312 MB) 
C before (nanoTime :362149.0034312 , 9.961990356445312 MB) 
C After    (nanoTime :362149.0118517 , 14.481971740722656 MB) 
C before (nanoTime :362149.0119602 , 14.481971740722656 MB) 
C After    (nanoTime :362149.0120124 , 14.481971740722656 MB) 
C before (nanoTime :362149.0120532 , 14.481971740722656 MB) 
C After    (nanoTime :362149.0121564 , 14.481971740722656 MB) 

----------------------------------------------------------------------------------------------------

2번까지 실행된 후 크게 변화는 없다.


A 코드를 짤 때 서늘함이 느껴져 가지고 실험을 해봤는데 

   이 정도 실험 결과면 나쁘지 않다.

 

<테스트 코드>

 

GitHub - oiNeh/code-test

Contribute to oiNeh/code-test development by creating an account on GitHub.

github.com

 

 

이제 안심하고 다시 코드 짜야지

 

 

 

편안-