프로그래밍/NodeJS

달새 메모리 최적화 기록

『하날엔☆。 2022. 1. 13. 18:58

달새 메모리 최적화 기록

최종 코드링크
달새 MK-IV의 경우 초기 메모리 최적화에 매우.. 실패를 했습니다.
메모리 최적화를 진행 하면서 몇가지 모델링을 정해놓고 진행을 했습니다.

  • 과거의 경험에서 나온 추론으로 string이 많은 게 문제일 것이다고 생각 하고 트위터에서 키값으로 주는 id_str을 전부 id: bigint로 변경
    • bigint로 했더니 JSON.stringyfy가 안 먹혀서 폐기.. 아니 대체 왜.......어이없다
  • 안 쓰는 값을 싹다 정리하고 interface형에서 class형으로 만들어서 생성자에서 쓰는 값만 할당
    • 추가로 new 연산 최소화하고 get property로 변경

  • 위에서부터 실제 사용중인 프로세스, 앞과 같은 버전, 켜놓고 방치
  • 아래 두 개의 프로세스는 동일하게 new, 오브젝트 생성을 최소화 한 버전. vue의 기본 __ob__제거 버전, 그냥 new 최소화만 한 버전

최종 선택은 가장 아래 그냥 new 최소화만 한 버전이 됐습니다.

내부 트윗 데이터 관리부터 알아야 합니다.

자체적으로 Tweet Object를 쉽게 쓰기 위해 orgTweet이라는 프로퍼티가 있습니다.
리트윗일 경우 retweeted_status라는 프로퍼티가 자식으로 있는데
해당 값이 리트윗 원본 데이터입니다.
그리고 리트윗 한 사람의 정보는 부모에 담겨있고요.
그래서 리트윗이 아닌 트윗, 리트윗인 트윗 둘 다 원본을 읽기 위해서 해당 값을 사용 하고 있습니다.
인용 트윗일 경우 자식으로 quoted_status가 있습니다.

new Tweet을 하던 곳

  • Vuex 모듈인 TweetStore.ts
  • 가상 스크롤 패널을 관리하는 ScrollPanelBase.tsCreateData(data: any)
  • TweetBase.tsget qtTweet
  • Tweet.ts의 생성자에서 orgTweet을 new 할당

new Tweet은 한 곳에서만

  • new Tweet(tweet)은 Vuex 모듈인 TweetStore.ts에서만 진행을 합니다.
    • 실제로는 다른데에서도 사용 하지만 최적화와 무관한 코드입니다.
      바뀐 Tweet 생성자 소스코드
 constructor(tweet?: Tweet) {
    if (tweet) {
      this.id_str = tweet.id_str;
      this.created_at = tweet.created_at;
      this.full_text = tweet.full_text;
      this.is_quote_status = tweet.is_quote_status;
      this.favorited = tweet.favorited;
      this.retweeted = tweet.retweeted;
      this.source = tweet.source;
      this.entities = tweet.entities;
      this.extended_entities = tweet.extended_entities;
      this.retweeted_status = tweet.retweeted_status;
      this.retweet_count = tweet.retweet_count;
      this.favorite_count = tweet.favorite_count;
      this.place = tweet.place;
      this.is_quote_status = tweet.is_quote_status;
      this.isRead = false;
      this.in_reply_to_status_id_str = tweet.in_reply_to_status_id_str;
      this.in_reply_to_user_id_str = tweet.in_reply_to_user_id_str;
      this.quoted_status_id_str = tweet.quoted_status_id_str;
      this.in_reply_to_status_id_str = tweet.in_reply_to_status_id_str;
      this.isDelete = false;
      this.user = new I.User(tweet.user);
      if (tweet.retweeted_status) {
        this.retweeted_status = new Tweet(tweet.retweeted_status);
      }
      if (tweet.quoted_status) {
        this.quoted_status = new Tweet(tweet.quoted_status);
      }
    } else {
        //..........
    }
  }

그리고 retweeted_status 아래와 같이 프로퍼티로 변경

  get orgTweet(): Tweet {
    if (this.retweeted_status) return this.retweeted_status;
    else return this;
  }

ScrollPanelBase.ts에서 CreateData를 폐기

new 연산 하던 걸 참조로 변경

  AddData(data: any, index: number) {
    const minHeight = moduleUI.minHeight;
    if (!this.stateData.setKey.has(data.id_str)) {
      this.stateData.setKey.add(data.id_str);
      const prev = this.stateData.listData[index - 1];
      const scrollTop = prev ? prev.scrollTop + prev.height : index * minHeight;
      const item: M.ScrollItem<any> = {
        data: data,//이 부분입니다.
        key: data.id_str,
        height: minHeight,
        isResized: true,
        scrollTop: scrollTop
      };
      this.stateData.listData.splice(index, 0, item);
    }
    if (this.isRendered()) {
      this.SetIndex();
    }
  }

__ob__제거 버전이 폐기된 이유

과거 MK-III개발 당시에 __ob__이 메모리를 상당히 먹는 문제가 있어 동일한 시도를 해보았으나
당시 사용하던 라이브러리의 메모리 누수로 추정될 정도로 메모리에 영향도가 없었기에
굳이 추가적인 로직 추가할 필요성을 못 느껴서 폐기했습니다.

마지막으로 트윗 최대 저장 수 지정

  • Vuex에서 들고있는 트윗의 최대 수를 1500개로 제한

위가 데이터 1500개를 들고있는 수준의 메모리입니다.
이정도로 1차 최적화는 만족을 하고 달새 메모리 최적화는 종료됩니다.

이 글의 교훈: new 작작하자