3

salesforce零基础学习(一百二十一)Limitation篇之Heap Size Limitation - zero.zhan...

 1 year ago
source link: https://www.cnblogs.com/zero-zyq/p/16876033.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

salesforce零基础学习(一百二十一)Limitation篇之Heap Size Limitation

 本篇参考:

https://help.salesforce.com/s/articleView?id=000384468&type=1

https://help.salesforce.com/s/articleView?id=000385712&type=1

此前讲过CPU limitation:salesforce零基础学习(一百零二)Limitation篇之 CPU Limit
本篇说一下项目中也经常用到的 heap size limitation以及best practice.
首先先说一下 salesforce中的 heap size简单概念, salesforce中的heap size和java中的heap size概念基本相同,当对象或者变量创建时,就会给分配内存,当运行时基于逻辑动态分配内存。salesforce限制同步最大的 apex heap size是6MB,异步的场景最多的是12MB. 当transaction执行时,太多数据存储在内存中的情况下,可能触发 The "Apex heap size too large" 的错误。

如果去调查某一个功能逻辑的heap size情况,可以通过以下的步骤来分析:

  • 通过debug log查看当前的 heap size情况。
  • 在debug log中通过HEAP_ALLOCATE来确定对象或者变量的分配内存的情况。
  • 通过最后的Maximum heap size: 了解当前的执行的transaction所使用的heap size情况。
  • 针对heap size limit拥有两个方法可以查询:
    1. Limits.getHeapSize():返回已用于堆的大致内存量(单位为:字节)。
    2. Limits.getLimitHeapSize(): 返回堆中还可以使用的大致的内存量(单位为:字节)

Best practice
1. 不使用class级别的变量去存储大量数据(也不一定局限于 class级别的变量,list尽量别存储大量数据)
错误案例: 下面的demo中: baseList,SampleMap的value以及tempt list都指向了同一个内存地址,执行以后,这个内存地址便会超限,从而触发The "Apex heap size too large" 的limitation

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,避免之前的内存倍速增长。

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>(); //Declare a new list

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());

2. 使用SOQL for loop从大量查询的数据中迭代和处理数据,官方也介绍了很多的 SOQL for loop的demo。详情可查看:

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_loops_for_SOQL.htm
未改进前的简单的demo如下:

List<Account> accs = [SELECT Id, Name FROM Account LIMIT 50000];

针对 heap size修改的情况下,官方给出的建议,此种情况下,每200条执行一次数据,大量的减少了 heap size的使用。

SOQL for loop通过调用SOAP API的query和queryMore方法,使用高效的分块来检索所有sObjects(每次处理200条数据)。开发人员可以通过使用SOQL for loop处理返回多条记录的查询结果来避免堆大小的限制。

for(Account a : [SELECT Id, Name FROM Account LIMIT 50000]){
//TODO custom logic
}

当然,在多租户环境下,我们的limitation也不止 heap size,上述方法是否是最优解需要具体情况具体分析。当我们使用 SOQL for loop并且数据量大的情况下,这种方法可能会导致使用更多的CPU周期,逻辑执行时间也变得多了。除了官方上面的链接介绍以外,也可以看一下下面的邱老板的demo

https://blog.keal.us/salesforce/soql-for-loop%e7%9a%84%e6%95%88%e7%8e%87%e9%97%ae%e9%a2%98/
3.
变量使用 'transient'关键字,用于声明不需要被保存的变量,并且在VF page情况下也不会计入view state

salesforce 零基础学习(四十二)简单文件上传下载

4. 在运行时环境下,通过在迭代list / set / map时从集合中移除不必要的item来减小堆大小。

除此以外的几点优化点作为参考:
1. 避免使用无效的临时变量。比如代码中的临时变量后续没有调用,造成了额外的花销,这种没有用的代码尽量删除。
2. 更短的命名以及Field api 名称: 诚然使用好的命名规范有更强的可读性,不过短的名字确实可以省一些 heap size
移除不必要的debug log语句,特别是生产环境。

总结:heap size和CPU limitation的优化相辅相成,不要为了某一个优化而特意放弃另外一个,彼此形成一下平衡。篇中有错误地方欢迎指出,有不懂欢迎留言。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK