ブログ

【Salesforce】Apex処理のガバナ制限におけるヒープサイズ制限による「System.LimitException: Batchable instance is too big」エラーの回避方法について

この記事をSNSでシェア!

はじめに

Salesforce のApex クラスを用いた開発の中で多くの開発者を悩ませるのが、特定のユーザーがサーバリソースを大きく使用し占有してしまい、他ユーザへ影響が及んでしまうことを防ぐことを目的として行われているガバナ制限です。
ガバナ制限の一つに、ヒープサイズ(Heap Size)による制限があります。

ヒープサイズとは、処理実行時に保持されるメモリサイズのことです。
大量データの取得や加工でデータを変数に一時退避する時には、ヒープサイズが上限を超過しないか注意が必要です。
ヒープサイズの上限(同期 6MB以下、非同期 12MB以下)を超過すると以下のようなエラーメッセージが表示されます。

“System.LimitException: Batchable instance is too big”

ヒープサイズ超過のエラーを回避するためにはどんな工夫ができるでしょうか。

まず第一に、見直すべきポイントは、処理で扱うデータ量です。取得するレコードの件数や、ループ処理の構造などを見直し、処理全体のヒープサイズを抑えます。
時には、データを蓄積する変数の種類を変更することによって、ヒープサイズが抑えられるケースもあります。

今回は、データを蓄積する変数の種類による、ヒープサイズの違いについて検証結果を具体的な数値と共に紹介いたします。

検証手順

データを蓄積する変数を、以下のパターンに分けてヒープサイズを比較します。

  • List クラスにて、要素のデータ型(String、Integer、内部クラス、カスタムオブジェクト)による違いを比較
  • Map クラスにて、Value のデータ型(String、Integer、内部クラス、カスタムオブジェクト、List<String>)による違いを比較
  • List クラスにて、要素(データ型:内部クラス、カスタムオブジェクト)の項目数による違いを比較

ヒープサイズの確認は、以下のようなApex クラスを実行し、ログに表示する値を確認します。
※本投稿内での「内部クラス」は、以下のソースのようにApex クラス内で定義し、複数の項目を定義することのできるものを指します

図1 Listクラスを用いた検証のソースコード
図2 Mapクラスを用いた検証のソースコード

検証結果

List クラスにて、要素のデータ型(String、Integer、内部クラス、カスタムオブジェクト)による違いを比較

List クラスの要素別ヒープサイズは、以下の通りです。

図3 List クラスのヒープサイズ検証結果

上記結果より、以下のことがわかります。

a) 一つの値を持たせる場合は内部クラス、カスタムオブジェクトを使用するよりも、String 型、Integer 型の単一の変数を使用した方がヒープサイズを抑えられる

b) データを蓄積する項目数が同一の場合、カスタムオブジェクトよりも内部クラスを使用した方がヒープサイズが半分程度に抑えられる

Map クラスにて、Value のデータ型(String、Integer、内部クラス、カスタムオブジェクト、List<String>)による違いを比較

Map クラスのvalue 別ヒープサイズは、以下の通りです。

図4 Map クラスのヒープサイズ検証結果

上記結果より、以下のことがわかります。

a) 一つの値を持たせる場合は内部クラス、カスタムオブジェクト、List を使用するよりも、String 型、Integer 型の単一の変数を使用した方がヒープサイズを抑えられる

b) 図3 と比較するとList よりMap を使用する方が全体的にヒープサイズが大きくなる

List クラスにて、要素(データ型:内部クラス、カスタムオブジェクト)の項目数による違いを比較

List クラスの項目数別ヒープサイズは、以下の通りです。
※内部クラス、カスタムオブジェクトの項目は全てString 型とする

図5 List クラスの項目数によるヒープサイズ検証結果

上記結果より、以下のことがわかります。

a) 内部クラス、カスタムオブジェクトの項目数の増加によってヒープサイズも増加する

項目数が5倍=ヒープサイズが5倍…のような単純計算にはなっていない点は注意が必要ですね。

おわりに

今回の検証では以下のようなことが確認できました。

  • List やMap よりも、String 型やInteger 型など単一の変数の方が、ヒープサイズが小さい
  • 複数の項目値をセットで保持したい場合、オブジェクト変数よりも内部クラスを使用した方がヒープサイズが小さい
  • 内部クラスやカスタムオブジェクトは、項目数に応じてヒープサイズが変動する

Apex クラス内で大量データの取得もしくは、加工をする場面でList やMap の使用は便利ですが、ヒープサイズを超過しないように注意が必要です。

本投稿にて、データを格納する変数の種類を使い分けることでヒープサイズを抑えることができると確認できました。ヒープサイズ超過エラー回避のヒントになれば幸いです。

ヒープサイズに限らず、多くの制限観点を持つガバナ制限とはうまく向き合いながらSalesforce 開発を進めていかなければと改めて感じました。
今後もSalesforce 開発の中で、困った点やその改善策などを共有していこうと思います。

投稿者プロフィール

日野 純子
日野 純子
はじめまして。BS事業部BSグループの日野です。

Salesforce を用いた開発業務に携わっております。
日々進化するSalesforce での開発における便利な方法を皆さまと共有できればと思います。
この記事をSNSでシェア!