• 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 baseList = tStr.split(' ');
    List bigList = baseList;
    Map> SampleMap = new Map>();
    SampleMap.put(1, bigList);
    
    for (integer i=0; i<50; i++) {
        List tempList = new List();
        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 baseList = tStr.split(' ');
    Map> Sample = new Map>();
    List bigList = baseList;
    
    Sample.put(1, bigList);
    List myList = new list(); //Declare a new list
    
    for (integer i=0; i<50; i++) {
        List tempList = new List();
        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 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的优化相辅相成,不要为了某一个优化而特意放弃另外一个,彼此形成一下平衡。篇中有错误地方欢迎指出,有不懂欢迎留言。

  • 相关阅读:
    【go语言基础】go类型断言 type switch + case,t := x.(type)
    Web APIs Web APIs第三天
    Postgresql事物快照介绍
    每日一题--658. 找到 K 个最接近的元素
    python Django的个人博客
    apriltag_ros简单上手
    【Linux】32条指令带你玩转 Linux !
    某汽车金融企业:搭建SDLC安全体系,打造智慧金融服务样本
    [阅读笔记20][BTX]Branch-Train-MiX: Mixing Expert LLMs into a Mixture-of-Experts LLM
    论文阅读-Detecting and Recovering Sequential DeepFake Manipulation(SeqFakeFormer)
  • 原文地址:https://www.cnblogs.com/zero-zyq/p/16876033.html