写在前面
控制系统内存是常见的一个话题,一般三维设计软件内存控制的普遍较好,当然一方面是开发时间较长,投入较多,当然另一方面也是相应的开发团队技术经验较丰富,有较好的系统架构和内存管理机制。当然也会有一些软件或产品内存控制的不好,用户使用体验较差。
博主混迹于CSDN已有数年,也有一些经验,适逢周末惬意,闲暇时光中进行一些总结记录以供自己和需要的人参考。
思考
系统逻辑较复杂,运行时内存占用较高且不稳定,该怎么办?
博主认为所谓系统逻辑复杂本是个伪概念,一个系统确实有逻辑复杂的部分,如复杂的专业计算部分,但只要系统结构合理,封装合理,系统架构应是比较简单清晰的,当然确实存在一些“逻辑复杂”的程序,大概是因为架构不合理,结构混乱吧。
首先要做的是将内存(或资源)管理(申请、使用、释放相关)部分进行封装,统一进行管理,如由统一的内存申请工具类和内存释放类,力求内存管理逻辑简单清晰,这样可方便的确保系统内存申请后不再使用时能够释放,避免内存泄漏的情况发生。
上一步做完后,内存问题会一定程度的得到缓解,内存问题可能不会完全解决,那么请继续思考。如果条件允许,请逐步进行系统重构,使得逻辑尽量清晰简洁。
系统中是否存在频繁申请、使用、释放的资源?
可以把频繁使用的内存进一步管理起来,申请和释放的入口进行管理,因为是频繁使用的,为了避免重复频繁的进行申请和释放,一个好的方式是进行缓存机制的建立。
设置一定的缓存上限(阈值),建立已使用的和未被使用部分的分区,如果需要申请该类型的资源,那么调用接口,由该资源管理类进行分配,先从未使用分区中获取,如果获取不到,即马上申请,然后丢到已使用的分区里面,同时返回给接口调用者。同样,如果使用者需要释放所拥有资源时,也同样调用接口,由该资源管理类进行“释放”:在已使用分区中剔除掉该资源,然后丢掉未使用分区中,即假释放,然后呢?如果你原因,返回true代表接口已成功“释放”资源吧。
如果达到上限怎么办?如果不对上限进行要求,那么系统内存是不稳定的:比如,打开处理一个小模型或是中等模型时,内存是“稳定的”,打开大模型或是超大模型时内存就是飙升的,这显然是系统内存问题,只不过属于另一个技术台阶了。
如果达到上限,可以一定程度的加大上限,或者即用即申,不用即释,如果系统内存比较容易达到上限,是否是释放的不够及时?可以把资源释放器提前,即不用的时候就马上释放,而不是达到某个阶段时统一释放。或者是否可以进行重构以减少频繁申请的程度?当然如果还不行,那么请继续看后续的分析及措施。
如果资源有唯一标识,并且缓存是为了减少重复计算的目的的话(即不缓存也可以,就是得重新计算一遍),可以在此基础上建立一套根据引用次数来精细化管理资源,比如达到上限后,就进行分析处理:将缓存中引用次数小于一定值的资源释放掉。此方式和.net的内存管理机制类似,有3代机制,如果达到上限,即清理第三代,第三代清理掉的不够的话,就继续去清理第二代...第一代,普遍来说第一代管理的资源生存周期更长,清理代价较高(清理一次可能清理的少),第三代资源生存周期短,清理代价低,很容易清理出足够的可用内存,这和调用栈相关联,资源也像压栈出栈,先压的后出。
值得一提的是内存和性能是关联的,较少资源的频繁申请释放和同时存在也会提升性能。
还可以使用设计模式来减少内存的占用。
如工厂模式、享元模式等,其中享元模式应用在元数据可以共享的场景,如全市中考,考生数可能几万甚至几十万,但考场数、科目数等是很有限的,这些就是可以共享的元数据,只有姓名等属于特定于考生的独特数据。
C++内存申请和释放机制
可利用C++的定制new和delete在预申请的内存上分配内存给资源,再加上一定的标记,就不需要释放内存这个动作,因为覆盖即可。
当然还可以利用智能指针来“智能”的释放资源,这里所谓智能,是不需要人工做过多的干预即可达到预定目的。
分批处理
这个话题接着上述话题,如果缓存达到上限了怎么继续处理?如果实际情况当一定体量的数据时总会达到上限的,那怎么办?可以分批处理,然后对结果合并,熟悉吗?对,就是归并排序那样!在实际使用时,分批处理也是很有效的方法,当然在决定进行该处理时请确保上述优化处理都已做过,在一个可靠的根基上进行关键问题的突破和解决是必要的。
那么有没有其它辅助分析方法能提高自己的开发优化效率呢?
可以使用VS的内存分析功能进行程序内存分析,还可以参考博主的文章:VS检测内存泄漏C++程序来进行内存泄漏点分析,然后针对性的优化,这种方法是很有效的,往往能否提升你的开发体验,使你心情平稳愉悦。
总结
上述方法可以有效的应对程序或系统内存问题,当然正如本文中所说的:在一个可靠的根基上进行关键问题的突破和解决是必要的。请优先确保或进行系统架构的合理和优化。