5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【メモリリーク】reactコンポーネントでfetch中にアンマウントするとメモリリークは起こるのか?

Last updated at Posted at 2023-02-20

結論

普通に使ってる分には起こらなさそう。

検証した環境

ライブラリ・FW バージョン
react 18.2
Next.js 13.14

今回のテーマ

  • HTTPリクエストの結果が返ってくる前にコンポーネントをアンマウントすると、メモリリークは起こるのか調べてみた。

ちょっと仕事でこの辺りの挙動について知りたくなったので調べてみました!

メモリリークとは

  • プログラムによってメモリを確保したものの
    解放されないままプログラムが終了してしまい
    ヒープ領域をムダにロックしちゃってる状態を指します。

reactで起こるメモリリーク

ではreactではどういうケースでメモリリークが起こるんでしょうか?
こちらの記事によると要因は以下の3つらしいです。

  • DOMイベントリスナー
  • WebSocket サブスクリプション
  • APIへのリクエスト

今回はAPIリクエストのレスポンスが返ってくる前にコンポーネントをアンマウントするとメモリリークが起こるのか検証していきたいと思います。
https://dev.to/jeremiahjacinth13/memory-leaks-how-to-avoid-them-in-a-react-app-1g5e#:~:text=Causes%20of%20Memory%20Leaks%20in,a%20request%20to%20an%20API

検証方法

こちらに2つのページを用意しました。

  • 1ページ目のボタンを押してからリンクを押すと、fetch中にTestコンポーネントをアンマウントし(DOMツリーから外し)てTest2コンポーネントを表示します。

そうするとレスポンスを返す先がなくなったPromiseオブジェクトだけが残ってメモリリークが起こるはず、、、!
ということで、その時のメモリの状態をdevtoolsのパフォーマンスタブから記録して眺めていきます。

// 1ページ目
const Test = () => {
  const [value, setValue] = useState(0);

  // あり得ないほどレスポンスが遅いAPIのダミー
  const neverEndingdummyRequest = () => {
    return new Promise((resolve, reject) => {
      // 10000秒後にstate更新
      setTimeout(() => {
        resolve(setValue(value + 1));
      }, 10000000);
    });
  };

  const handleValue = async () => {
    await neverEndingdummyRequest();
  };

  return (
    <>
      <p>{value}</p>
      <button onClick={handleValue}>request</button>
        <Link href="/test2">test2</Link>
    </>
  );
};
// 2ページ目
const Test2 = () => {

  return (
    <>
      <p>test2</p>
      <Link href="/test">testへ</Link>
    </>
  );
};

何もしない場合

  • まず何もしない場合のメモリです。青い線がJSのメモリです。
    20秒の間219MB~225MBの間で変化していますが、グラフはほぼ平坦です。
    スクリーンショット 2023-02-21 1.00.42.png

リクエスト・アンマウントしまくる

  • 次に40秒間リクエストとページ遷移を繰り返しまくった時のメモリです。
    右肩上がりにメモリの使用量が増えてますね。
    しかしメモリリークしているなら操作をやめてもグラフは減らないはずです。これではやめた後どうなっているのかわかりません。次はその辺りを検証してみましょう。

スクリーンショット 2023-02-21 1.01.47.png

泥臭くリクエストとアンマウントを繰り返す図
ezgif.com-crop.gif

リクエスト・アンマウントしまくった後、何もしない

  • 17秒くらいまでリクエストとページ遷移を繰り返しまくった後、終わるまで放っておいた時のグラフです。
    グラフを見るにメモリリークは起きてなさそうです。
    スクリーンショット 2023-02-21 1.01.47.png

最後に

今回の記事での環境以外にも色々と検証してみたんですが、結局メモリリークを再現できませんでした。

ちなみにreact18.2での検証でしたが、react18以前ではメモリリークを警告するエラーが出てたそうです。
しかしこの警告もAPIについての文脈じゃなさそうなので、考慮しなくて良さそう。

結論としてはあまりメモリリークを意識してreactを書く必要はなさそうってところですかね...
なんか釈然としないですが今回はこんなところで終わろうと思います。

お読みいただきありがとうございました!

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?