6.3 临时对象

Q1:讨论一下三种语句产生临时对象的情况

    //1.
         T c = a + b;
    //2. 
        c = a + b;
    //3.
         a + b;
  • 第一种情况,实现时不会产生临时对象,可能会直接以拷贝构造的情况,将 a + b 的值放入 c 中,或是直接进行NRV优化,导致直接在对象 c 中求值操作

以下讨论另外两种情况



Q2:对 c = a + b 的情况

• 这种情况下会产生临时对象,具体代码情况如下:

    // T temp = a + b;
    T temp;
    temp.oprator+(a,b);    // (1)
    //c = temp;
    c.operator=(temp);     // (2)
    temp.T::~T()

• 上述的句子(1),未构造的临时对象被赋值给operator+(),这意味着:表达式的结果被复制构造至临时对象中,或者以临时对象进行NRV

• 直接传递 c 到运算符函数(2)中都是有问题的,因为该对象不是一个新定义的对象,而运算符函数不为其外加参数调用析构函数,所以在调用运算符函数前必须要先调用析构函数

• 因此,该语句将会被转换为如下形式:

        c.T::~T();
        c.T::T(a + b);          //产生临时对象存储 a + b

由于原语句希望调用赋值操作符函数,而转换后的语句调用析构函数与复制构造函数,因此可能转换前后语意不同,是不安全的,而且会产生临时对象

• T c = a + b 总是比 c = a + b 更有效的被编译器转换出来



Q3:对 a + b 的情况

• 会产生临时对象用来存放其值,这种情况下重点关注“临时对象的生命期

• 考虑以下例子:

Eg:

        string s,t;
        print("%s\n",s + t);

其中 s + t 将产生一个临时对象,分析该临时对象的生命期

• 下面是对该算是的一个可能的早期标准转换,虽然语法正确,但是很有问题:

Eg:

        string temp1 = operator+(s,t);
        const char * temp2 = temp1.operator const char*();   //转换操作符

        temp1.~string();     //销毁temp1

        printf("%s\n",temp2);      //此时temp2 指向一个被释放的内存

• C++ 标准规定,临时对象的摧毁应该是对完整表达式求值过程中的最后一个步骤

• 当临时性对象是根据程序的执行期语意,有条件的被产生出来时,临时对象的生命规则就有些复杂

Eg:

    if(s + t || u + v);

只有当 s + t 的值为 false 时,才会计算 u + v 的值。因此,必须先知道临时对象是否被产生,才能确定是否应该在表达式结束前销毁临时对象

• 解决方法是:某些形式的条件测试必须被安插进来,以决定是否要摧毁和第二个算式有关的临时对象

• 临时对象的声明规则有两个例外:

1. 当表达式被用来初始化一个对象时,要求持有该表达式执行结果的临时对象,应该存留到对象的初始化操作完成为止。但注意以下情况:

Eg:

            string n,s;
            cpmst char * ns = n + s;

        //会转化为如下情况:

            string temp;
            operator+(temp,n,s);
            ns = temp.string::operator char *();

         //此时对象的初始化操作已完成,才销毁临时对象,但是该销毁操作将会导致 ns 指向一个未定义的堆内存
            temp.string::~string();         

2. 当一个临时对象被一个引用绑定时,此时临时对象将残留,直到该引用的生命结束,或者临时对象的 scope 结束。如:

Eg:

            const string &space = " ";

            //会转化为如下情况:

            string temp;
            temp.string::string(" ");
            const string & space = temp;

此时如果销毁临时对象temp,则该引用将没有任何用处

### 解决方案概述 为了减少模型运行时的内存需求或将可用内存量从4.6 GiB增加到6.3 GiB,可以采取多种策略来优化系统性能和资源分配。这不仅涉及调整虚拟机配置参数,还包括操作系统级别的调优措施。 ### 减少模型内存占用的方法 通过精简模型架构、量化权重以及采用更高效的存储格式能够有效降低模型本身的内存消耗: - **模型剪枝**:移除神经网络中不重要的连接或节点,在保持较高精度的同时显著减小模型大小。 - **权重量化**:将浮点数转换成整型或其他低精度数值表示形式,从而节省大量空间并加速计算过程[^1]。 - **混合精度训练**:利用半精度(FP16)代替单精度(FP32),进一步压缩模型尺寸而不明显影响预测效果。 ### 增加物理内存的有效方法 当现有硬件条件无法满足应用需求时,则需考虑扩展实际安装的RAM容量;然而在此之前还可以尝试以下软件层面的技术手段提升可支配内存总量: - **释放缓存数据**:清除不必要的文件缓冲区和其他临时对象所占有的部分工作集,以便腾出更多连续的大页区块供后续操作使用。 ```bash echo 3 > /proc/sys/vm/drop_caches ``` - **紧缩碎片化的地址空间**:执行特定命令让Linux内核重新排列进程映射表项的位置,有助于获取更大范围内的未分配区域作为新的大页面容器。 ```bash sysctl vm.compact_memory=1 ``` - **等待一段时间再启动VM**:由于长时间运行可能导致剩余空闲片段难以拼接成完整的巨型帧结构,因此建议稍作停顿后再创建新实例以提高成功率。 ### 提升交换分区效率 如果仍然面临严重的内存瓶颈问题,那么适当增大swap分区规模也是一种可行的选择。尽管访问速度较慢,但在某些场景下确实能起到缓解作用: ```bash fallocate -l 8G /mnt/8GB.swap chmod 600 /mnt/8GB.swap mkswap /mnt/8GB.swap swapon /mnt/8GB.swap echo '/mnt/8GB.swap swap swap defaults 0 0' >> /etc/fstab ``` 上述代码用于创建额外的8 GB交换文件,并将其激活加入系统的分页机制当中去。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值