Loading

'Apex 힙 크기 너무 큼' 오류

게시 일자: Oct 13, 2022
상세 설명

Salesforce는 동기식 트랜잭션의 경우 6MB, 비동기식 트랜잭션의 경우 12MB의 Apex 힙 크기 제한을 적용합니다.

처리 과정에서 메모리에 너무 많은 데이터가 저장될 경우 'Apex 힙 크기가 너무 큼' 오류가 발생합니다. 크기 제한은 실행 유형(예: 동기 또는 비동기 호출)에 따라 다르고, 현재 값은 Apex 개발자 가이드에서 확인할 수 있습니다.

코드를 검토하고 모범 사례를 따라 힙 한도가 최댓값을 초과하지 않도록 하는 것이 중요합니다. 

다음은 힙 크기 한도를 초과하게 될 Apex 코드의 예입니다. 
 

@isTest
private class heapCheckIssue{
    static testMethod void myTest(){
        String tStr = 'aaaaa bbbbb ccccc ddddd eeeeee fffff ggggg 11111 22222 33333 44444';
        List<String> baseList = tStr.split(' ');
        List<String> bigList = baseList;
        Map<integer, List<String>> SampleMap = new Map<integer, List<String>>();
        SampleMap.put(1, bigList);
        
        for (integer i=0; i<50; i++) {
            List<String> tempList = new List<String>();
            tempList = SampleMap.get(1);
            bigList.addAll(tempList);
        }
        system.debug('FINAL LIST SIZE IS '+bigList.size());
    }
}
위는 올바르지 않은 컬렉션 사용의 예입니다. 
List baseList와 SampleMap의 값과 List tempList는 동일한 메모리 주소를 가리킵니다. 그 결과 루프가 반복될 때마다 힙 크기가 두 배로 증가합니다.

 

 

솔루션

다음은 힙 크기를 초과하지 않을 유사한 알고리즘의 예입니다. 
 

@isTest

private class heapCheckSuccess{
  static testMethod void myTest(){
    String tStr = 'aaaaa bbbbb ccccc ddddd eeeeee fffff ggggg 11111 22222 33333 44444';
    List<String> baseList = tStr.split(' ');
    Map<integer, List<String>> Sample = new Map<integer, List<String>>();
    List<String> bigList = baseList;

    Sample.put(1, bigList);
    List<string> myList = new list<string>(); //새 목록을 선언

    for (integer i=0; i<50; i++) {
      List<String> tempList = new List<String>();
      tempList = Sample.get(1);
      system.debug('templist: ' + tempList.size());
      system.debug(' bigList: ' + bigList.size());

      myList.addall(tempList); //original code is  bigList.addall(tempList);
    }

    system.debug('FINAL LIST SIZE OF bigList IS '+ bigList.size());
    system.debug('myList IS '+mylist.size());
  }
}
위 예에서는 bigList 변수를 사용하지 않고 새 List를 사용하여 각 반복 실행의 tempList 값을 저장한 다음 목록을 추가하므로 힙 크기가 너무 커지지 않습니다.


Apex 힙 크기 이내에서 실행하는 모범 사례

  • 클래스 수준 변수를 사용하여 데이터를 대량으로 저장하지 마세요.
  • SOQL For Loops를 이용하여 반복하고 큰 쿼리의 데이터를 처리하세요.
  • 변수가 더 이상 필요하지 않으면 즉시 범위를 벗어날 수 있게 허용하는 방법과 루프를 구성하세요.


아래 샘플에서는 50,000개의 항목을 처리할 수 있지만, 가장 큰 힙에 검색어, 쿼리, 200개 계정의 목록, 그리고 결과 목록이 하나씩 포함됩니다. 처리되는 모든 것을 감안하면 이 수는 상대적으로 작다고 할 수 있습니다.
 

public with sharing class myClass{

private String myString;

    public myClass(String searchString) {
        myString = searchString;
    }

    private string getQueryString() {
        return 'SELECT Id, Name FROM Account LIMIT 50000';
    }

    public List<Account> getSearchResults() {
        List<Account> searchResults = new List<Account>();
        for(List<Account> accts : Database.Query(getQueryString())) {
            // 각 루프가 200개의 항목을 처리
            for(Account a : accts) {
                if (a.Name != null && a.Name.contains(myString)) {
                    searchResults.add(a);
                }
            }
        }
        return searchResults;
    }
}
 

이 주제에 대한 자세한 내용은 SOQL For Loops 관련 문서에서 확인하세요.

Knowledge 기사 번호

000384468

 
로드 중
Salesforce Help | Article