![]() |
1
30
我的经验来自 极其 受限的嵌入式内存环境:
|
![]() |
2
13
你可以做很多事情来减少你的记忆足迹,我相信人们都写过关于这个主题的书,但其中一些主要的是:
|
![]() |
3
11
一些明显的
将知识折叠成数据规则之一 Unix philosophy 有助于使代码更紧凑:
我不知道我见过多少次复杂的分支逻辑,跨越许多页,可以折叠成一个规则、常量和函数指针的紧凑表。状态机通常可以这样表示(状态模式)。命令模式也适用。这都是关于声明式和命令式编程风格的。 日志代码+二进制数据而不是文本而不是记录纯文本、日志事件代码和二进制数据。然后使用“短语簿”重新构造事件消息。短语手册中的消息甚至可以包含printf样式的格式说明符,以便事件数据值在文本中整齐显示。 最小化线程数每个线程都需要自己的内存块用于堆栈和TSS。如果您不需要抢占,可以考虑让您的任务在同一线程内协同执行。( cooperative multi-tasking ) 使用内存池而不是囤积为了避免堆碎片化,我经常看到单独的模块为了自己的使用而存储大量的静态内存缓冲区,即使只是偶尔需要内存。可以使用内存池来代替,因此只能“按需”使用内存。但是,这种方法可能需要仔细的分析和检测,以确保运行时池不会耗尽。 仅在初始化时进行动态分配
在只有一个应用程序无限期运行的嵌入式系统中,您可以以一种不会导致碎片化的合理方式使用动态分配:只在各种初始化例程中动态分配一次,而不释放内存。
|
![]() |
4
7
从链接器生成映射文件。它将显示如何分配内存。在优化内存使用时,这是一个很好的开始。它还将显示所有函数以及代码空间的布局方式。 |
![]() |
5
7
与所有优化一样,首先优化算法,然后优化代码和数据,最后优化编译器。 我不知道你的程序是做什么的,所以我不能对算法提出建议。还有很多人写过关于编译器的文章。下面是一些关于代码和数据的建议:
|
![]() |
6
5
|
![]() |
7
4
用vs/os编译。通常情况下,这甚至比优化速度更快,因为更小的代码大小==更少的分页。 应该在链接器中启用COMDAT折叠(在发布版本中是默认的) 注意数据结构的打包;这通常会导致编译器生成更多代码(=more memory)来生成程序集以访问未对齐的内存。 Using 1 bit for a boolean flag is a classic example. 另外,在选择一个内存高效的算法而不是运行时间更好的算法时要小心。这就是过早的优化出现的地方。 |
![]() |
8
3
好吧,大多数人都已经提到过了,但这是我的清单:
最后但并非最不重要-同时寻找最小可能的代码大小- 不要过火 它。还要注意性能和可维护性。过度优化的代码往往会很快衰减。 |
![]() |
9
2
首先,告诉编译器优化代码大小。海湾合作委员会有
其他的一切都是在算法层面上的——使用类似的工具来查找内存泄漏,而是寻找可以避免的分配和释放。 还可以看看常用的数据结构打包——如果您可以将它们切掉一两个字节,就可以大大减少内存使用。 |
![]() |
10
2
如果您正在寻找一种分析应用程序堆使用情况的好方法,请查看valgrind的 massif 工具。它可以让你在一段时间内对你的应用程序的内存使用情况进行快照,然后你可以利用这些信息更好地了解“低挂水果”的位置,并相应地瞄准你的优化。 |
![]() |
11
2
|
![]() |
12
2
最重要的是其他人的建议: 限制使用C++的特性,在ANSIC中写得很小。标准(std::)模板使用大型动态分配系统。如果可以,请完全避免使用模板。虽然它们本身并不有害,但它们使得仅仅从几个简单、干净、优雅的高级指令中生成大量机器代码变得过于容易。这鼓励了以一种方式编写——尽管有“干净的代码”的所有优点——非常需要内存。 如果必须使用模板,请编写自己的模板或使用为嵌入使用而设计的模板,将固定大小作为模板参数传递,并编写测试程序,以便测试模板并检查-s输出,以确保编译器不会生成可怕的程序集代码来实例化模板。 手动调整结构,或使用pragma pack
出于同样的原因,使用集中的全局数据存储结构,而不是分散的局部静态变量。 智能地平衡malloc()/新结构和静态结构的使用。 如果您需要给定库的功能子集,请考虑编写自己的库。 展开短循环。
长于
长的不要这样做。 将多个文件打包在一起,让编译器内联短函数并执行链接器不能执行的各种优化。 |
![]() |
13
1
不要害怕在程序中编写“小语言”。有时一个字符串表和一个解释器可以完成很多工作。例如,在我工作过的系统中,我们有许多内部表,这些表必须以各种方式访问(循环,无论什么)。我们有一个用于引用表的内部命令系统,这些表形成了一种中间语言,对于它得到的DONW来说非常紧凑。 但是,小心点!知道你在写这样的东西(我自己不小心写了一篇),并记录下你在做什么。最初的开发人员似乎没有意识到他们在做什么,所以管理起来比应该的要困难得多。 |
![]() |
14
1
优化是一个流行的术语,但在技术上常常是错误的。它的字面意思是使最佳。无论是速度还是尺寸,这种情况实际上都无法实现。我们可以简单地采取措施走向优化。 许多(但不是全部)用于向最小时间移动到计算结果的技术牺牲了内存需求,而许多(但不是全部)用于向最小内存需求移动的技术延长了结果的时间。 减少内存需求相当于固定数量的通用技术。很难找到一种不完全适合其中一种或多种技术的特定技术。如果你做了所有这些,如果不是绝对最小可能的话,你将得到一个非常接近程序最小空间需求的东西。对于一个真正的应用程序,需要一个由经验丰富的程序员组成的团队一千年才能完成。
这是一个关于这个主题的计算机科学视图,而不是开发人员的视图。 例如,打包数据结构是将上述(3)和(9)结合起来的工作。压缩数据是至少部分实现上述(1)的一种方法。减少更高级别编程结构的开销是实现(7)和(8)中某些进展的一种方法。动态分配是一种利用多任务环境的尝试(3)。编译警告,如果打开,可以帮助(5)。破坏者试图协助(6)。插座、溪流和管道可用于完成(2)。简化多项式是在(8)中获得基础的一种技术。 理解“九”的含义以及实现“九”的各种方法是多年学习和检查记忆地图的结果。由于可用内存有限,嵌入式程序员通常更快地学习它们。 在GNU编译器上使用-os选项向编译器发出请求,试图找到可以转换的模式来完成这些任务,但是-os是一个聚合标志,它打开许多优化功能,每个功能都试图执行转换来完成上面9个任务中的一个。 编译器指令可以在不需要程序员努力的情况下产生结果,但是编译器中的自动化进程很少纠正由于代码编写者缺乏意识而产生的问题。 |
![]() |
15
0
请记住一些C++特性的实现成本,例如创建临时对象的虚拟函数表和重载运算符。 |
![]() |
16
0
除此之外,其他人都说,我只是想补充一点,不要使用虚拟功能,因为对于虚拟功能,必须创建一个vtable,它可以占用谁知道有多少空间。
还要注意例外。对于gcc,我不认为每个try-catch块的大小都在增加(除了2个函数)
|
![]() |
Hatsune Miku · 比较或if语句是否更快[已关闭] 1 年前 |
![]() |
Black Swan · 无法解压缩的值太多(应为2)错误 1 年前 |
![]() |
Kai · 有什么方法可以轻松优化VSCode中的锈迹? 2 年前 |
![]() |
Balfar · 处理NumPy阵列上的循环最有效的方法是什么? 3 年前 |
![]() |
Daniel · C#轻松存储快速访问的大型位矩阵 7 年前 |
|
halbe · 优化音频DSP程序的numpy计算 7 年前 |
![]() |
Afsara · 是否有任何方法不能优化我们的应用程序? 7 年前 |