RORK LABEN
DEADLINE — Google Play の Android 16(API レベル36)必須化まで残り4日です。8月31日以降、新規アプリも既存アプリの更新も対象となりますRULES — 提出ルールと可視性ルールは別物です。更新を止めているアプリも、API 35 未満のままだと新しい端末で新規ユーザーに表示されなくなりますEXTENSION — 延長を申請すれば11月1日まで全ユーザーへの配信を続けられます。フォームは Play Console から出るため、締切前に済ませておく必要がありますEXPO — Expo SDK 57 は React Native を 0.85 から 0.86 へ引き上げ、React は 19.2 で据え置きです。0.86 は破壊的変更がない想定とされていますHERMES — 57.0.9 が React Native 0.86.2 に更新し、SDK 56 の Hermes V1 メモリ退行を解消しました。reanimated や worklets を使うアプリで効きますPREBUILD — expo prebuild が native の android・ios ディレクトリを既定でクリアして再生成します。手を入れた native 変更は、事前に洗い出さないと静かに失われますDEADLINE — Google Play の Android 16(API レベル36)必須化まで残り4日です。8月31日以降、新規アプリも既存アプリの更新も対象となりますRULES — 提出ルールと可視性ルールは別物です。更新を止めているアプリも、API 35 未満のままだと新しい端末で新規ユーザーに表示されなくなりますEXTENSION — 延長を申請すれば11月1日まで全ユーザーへの配信を続けられます。フォームは Play Console から出るため、締切前に済ませておく必要がありますEXPO — Expo SDK 57 は React Native を 0.85 から 0.86 へ引き上げ、React は 19.2 で据え置きです。0.86 は破壊的変更がない想定とされていますHERMES — 57.0.9 が React Native 0.86.2 に更新し、SDK 56 の Hermes V1 メモリ退行を解消しました。reanimated や worklets を使うアプリで効きますPREBUILD — expo prebuild が native の android・ios ディレクトリを既定でクリアして再生成します。手を入れた native 変更は、事前に洗い出さないと静かに失われます
記事一覧/開発ツール
開発ツール/2026-08-27中級

メモリが膨らむ原因を自分のコードに探す前に、worklet の数を数えてください

Hermes V1 は worklet 1つにつき 512KB のデバッグ用メタデータを積みます。Reanimated を読み込むだけでメモリが増える仕組みと、自分のコードを疑う前に数えるべき3つの数字、そして4通りの直し方の選び分けをまとめました。

Hermes8React Native Reanimatedreact-native-workletsExpo SDK 574メモリ4

壁紙アプリの実機を Xcode につないで、メモリのゲージを眺めていた夜がありました。起動直後に想定より数十MB多い。落ちるほどではないけれど、以前の版ではこの位置になかったはずの線です。

まず疑ったのは自分のコードでした。画像のキャッシュ上限、プリフェッチの本数、一覧のセル再利用。順番に削っては測り直して、それでも線はほとんど動きませんでした。

原因は、私が書いた行の外にありました。

増えていたのはアニメーションではなく、デバッグ用のメタデータでした

Hermes V1 は旧 Hermes の改良版ではなく、実行のしくみから作り直されたエンジンです。コードを評価するときに、デバッグに役立つメタデータを一緒に持ちます。

react-native-reanimated は、アニメーションの計算を JS スレッドから逃がすために react-native-worklets を土台に使っています。従来の方式(Legacy Eval Mode)では、アニメーション関数のコードを文字列としてもう一つの JavaScript ランタイムへ送り、UI スレッド上でその場で評価します。

つまり、本番ビルドでも eval に相当する経路を通ります。そしてその経路に、Hermes V1 はデバッグ用のメタデータを付けていました。

Reanimated の開発元である Software Mansion の調査によると、その量は 一意な worklet 1つあたり 512KB。同社の記事では、初期化のために評価される worklet だけで100個を超え、起動時点で少なくとも 50MB になると説明されています。Expensify のバンドルには1,000個以上の一意な worklet があり、すべて評価されれば 0.5GB を超えうる、という数字も挙がっています(実際には遅延評価なので、全画面を触り尽くさない限りそこまでは行きません)。

私が削っていた画像キャッシュは、そもそも桁が違う場所でした。

自分のコードを疑う前に、3つ数えます

順番を間違えると、私のように何時間も自分のコードを削ることになります。先に数えるべき数字が3つあります。

1. そもそも worklets が依存に入っているか

npm ls react-native-reanimated react-native-worklets

Rork が生成したプロジェクトは、画面遷移やジェスチャの実装でこの2つに触れていることがほとんどです。直接 import していなくても、依存の依存として入っていれば対象になります。

2. 自分が書いた worklet の数

grep -rhoE "['\"]worklet['\"];" src | wc -l
grep -rcE "['\"]worklet['\"];" src

1行目が総数、2行目がファイル別の内訳です。ただしこれは下限です。Worklets の Babel プラグインは useAnimatedStyleGesture のコールバックを、明示的なディレクティブがなくても自動的に worklet 化します。手で 'worklet'; と書いた分しか拾えない点は割り引いて読んでください。

3. 期待される増分の桁

python3 -c "n=3; base=100; print(f'{n+base} worklet → 約 {(n+base)*512/1024:.0f} MB')"
# 103 worklet → 約 52 MB

n に自分の数、base にライブラリの初期化分(100前後)を入れます。ここで出る数字と、実機で見えている増分の桁が合うなら、探す場所は自分のコードではありません。

私の場合、この計算をした時点で捜索を打ち切りました。削るべきものが自分の側になかったからです。

直し方は4つあり、選ぶ基準は「何を動かしたくないか」

Hermes 側の修正はすでに取り込まれています。手元でどう受け取るかに、4通りの経路があります。

経路やること向いている状況
Expo を上げるexpo@57.0.9 以上へ(React Native 0.86.2 を含む)SDK 57 系にいて、上げる余地がある場合。最短
Bundle Mode を有効にするWorklets の Bundle Mode に切り替えるWorklets の新機能にも追随したい場合。Metro 側の設定が必要
Bytecode オプションBabel プラグインの実験的な hermesBytecode を使うMetro を触りたくない、RN も上げられない場合
Hermes を固定する修正がバックポートされた 0.15 系に固定Worklets の内部挙動を一切変えたくない場合

Bundle Mode は、コードの文字列を1つずつ送るのではなく、バイトコードのバンドル全体を副ランタイムへ見せる方式です。Hermes は mmap で遅延読み込みするため、追加コストがほとんど発生しません。Software Mansion は、この問題とは関係なく性能面でも Bundle Mode を推奨しています。

上流の React Native 0.87 を待つ、という5つ目の選択肢もあります。ただ「待つ」を選ぶなら、待っている間ずっとその 50MB を抱えたまま配信することになる、という前提だけは置いておきたいところです。

私は「上げる」を選び、上げられない条件を先に潰しました

4つのうち、私が選んだのは Expo を上げる経路でした。理由は単純で、Worklets の設定を変える経路は、後から誰か(未来の自分を含む)が「なぜこの設定があるのか」を思い出せなくなるからです。バージョンを上げただけなら、履歴を見れば理由がわかります。

個人開発でアプリを何本も抱えていると、この「説明の要らなさ」が効いてきます。設定を1つ足すたびに、その理由を覚えておく責任が全リポジトリぶん増えるからです。私はこの判断を、性能ではなく維持のしやすさで決めました。

ただし SDK 57 は expo prebuild の既定が変わっていて、iosandroid を消してから再生成します。手で編集したネイティブ設定があると、上げる作業そのものが別の問題を連れてきます。この点はExpo SDK 57 に上げる前に、prebuild で消えるネイティブ変更を洗い出すで手順にしてありますので、上げる前にそちらを通してください。

上げた後に確認するのは、次の2つだけで足ります。

npm ls expo react-native
# expo@57.0.9 以上 / react-native@0.86.2 以上
npx expo-doctor@latest

そして実機で、上げる前と同じ画面を同じ順番で開いてメモリを見ます。同じ経路をたどらないと、比較になりません。

数えてから上げると、上げた後の判断が変わります

この件で私が持ち帰ったのは、Hermes の知識よりも順番のほうでした。メモリが増えたとき、最初にすることは自分のコードを削ることではなく、増分の桁を見積もることです。桁が合わなければ、原因は別の階層にあります。

もし今、Reanimated を使うアプリで説明のつかないメモリを抱えているなら、まず npm ls expo react-native を打ってバージョンを見てください。それだけで、これから数時間かける先が決まります。

メモリの上限そのものを設計する話(解放の段階分けや、強制終了として記録されない終了の読み方)は、Rork iOSアプリのメモリプレッシャー対策のほうにまとめてあります。ランタイム側の原因を潰した後で、まだ余裕がないときに読む順序が自然だと思います。

私自身、今回は数える前に手を動かして遠回りをしました。同じ夜を過ごす方が一人でも減れば嬉しいです。お読みいただきありがとうございました。

シェア

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

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

開発ツール2026-05-27
Rork × Hermes を本番で2ヶ月運用した所感 — 初回起動とメモリの実測値
Rorkで生成したアプリのHermesを有効にしたまま2ヶ月本番運用した実測記録です。初回起動が38%短縮された中身、Pixel 7でメモリ18%減、クラッシュフリー率の推移と注意点を、広告収益と直結する個人開発の運用感覚から振り返ります。計測環境も明記しています。
開発ツール2026-08-14
Expo SDK 57 に上げる前に、prebuild で消えるネイティブ変更を洗い出す
Expo SDK 57 では expo prebuild が既定で ios と android を消してから再生成します。手編集を上げる前に洗い出す方法、config plugin への移し替え、57.0.9 で解消したメモリ回帰までを実務の順序でまとめました。
開発ツール2026-08-09
Hermes バイトコードの差分更新を実測する — モジュール1本の追加が更新サイズを29倍にした
2.4MB の Hermes バイトコードで OTA 差分を実測しました。1行の変更は 2,104 バイト、モジュールを1本足すと 61,197 バイト。よく言われるモジュールID安定化はほぼ効かず、効いたのは別の2つでした。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →