我一直想知道如何在我的下一个项目中管理记忆。这是在C / C ++中编写DSL。
可以通过三种方式中的任何一种来完成。
社区可能已经对这些方法中的每一种都有很多经验。哪一个会更快?每种方法的优缺点是什么?
一个相关的问题。 malloc / free会不会比在程序开始时分配一个大块并运行我自己的内存管理器慢? .NET似乎做到了。但我很困惑为什么我们不能指望操作系统比我们自己做的更好,更快地完成这项工作。
答案 0 :(得分:8)
一切都取决于!这是一个非常开放的问题。它需要一篇文章来回答它!
嘿..这是以前有人准备的人:
http://lambda-the-ultimate.org/node/2552
http://www.hpl.hp.com/personal/Hans_Boehm/gc/issues.html
这取决于您的对象有多大,有多少对象,分配和丢弃的速度,您希望投入多少时间进行优化和调整以进行优化。如果你知道你需要多少内存的限制,为了获得快速的性能,我认为你不能真正地从前面的操作系统中获取所需的所有内存,然后自己管理它。
从操作系统缓慢分配内存的原因是它处理磁盘和内存中的大量进程和内存,因此要获取内存,必须确定是否有足够的内存。可能,它可能必须将另一个进程内存从ram分配到磁盘,以便它可以为您提供足够的内存。还有很多事情要发生。因此,自己管理(或使用GC收集的堆)比为每个请求访问操作系统要快得多。此外,操作系统通常会处理更大的内存块,因此它可能会使您发出的请求大小变小,这意味着您可能会浪费内存。
你有超快速的真正硬性要求吗?许多DSL应用程序不需要原始性能。我建议你选择最简单的代码。您可以花一辈子时间编写内存管理系统,并担心哪种方式最好。
答案 1 :(得分:4)
呃......这取决于你为你的DSL编写垃圾收集系统的方式。 C或C ++都没有内置的垃圾收集工具,但它们都可以用来编写效率非常高或非常低效的垃圾收集器。顺便说一下,写这样的东西是一项非常重要的任务。
DSL通常用更高级别的语言编写,例如Ruby或Python,因为语言编写者可以利用垃圾收集和语言的其他功能。 C和C ++非常适合编写完整的,工业级的语言,但你肯定需要知道你正在做什么来使用它们 - yacc和lex的知识在这里特别有用,但是对dynamic memory management的一个很好的理解是正如你所说,也很重要。如果您仍然喜欢C / C ++中DSL的想法,您还可以查看用C编写的开源音乐DSL keykit。
答案 2 :(得分:4)
为什么垃圾收集C比C ++快?唯一可用于C的垃圾收集器是非常低效的东西,更多的是设计用于插入内存泄漏而不是实际提高代码质量。
在任何情况下,C ++都有可能用更少的代码达到更好的性能(请注意,它只是一种潜力。编写比同等C慢得多的C ++代码也很有可能。)
考虑到两种语言的当前状态,GC目前无法提高代码的性能。 GC可以在为其设计的语言中非常高效。 C / C ++不在其中。 ;)
除此之外,这是不可能的。语言没有速度。问哪种语言更快是没有意义的。它取决于1)特定代码,2)编译它的编译器,以及3)它运行的系统(硬件和操作系统)。
malloc是一个相当慢的操作,比.NET等价物慢得多,所以是的,如果你执行了很多小的分配,你可能最好分配一个大的内存池一次,然后使用那个块。
原因是操作系统必须找到一块空闲的内存,基本上是遵循所有空闲内存区域的链表。在.NET中,new()调用基本上只是将堆指针移动到分配所需的字节数。
答案 3 :(得分:3)
对于大多数垃圾收集实现,分配可以看到速度提升,但是你有额外的收集阶段成本,可以在程序执行的任何时候触发,导致突然(看似随机)的延迟。 / p>
至于你的第二个问题,这取决于你的内存管理算法。您可以安全地坚持使用库的默认malloc实现,但是有一些替代方案可以提供更好的性能。
答案 4 :(得分:1)
一个相关的问题。 malloc / free会不会比在程序开始时分配大量的chuck并在其上运行我自己的内存管理器慢? .NET似乎做到了。但我很困惑为什么我们不能指望操作系统比我们自己做的更好,更快地完成这项工作。
让操作系统处理内存分配的问题在于它引入了不确定的行为。程序员无法知道操作系统返回新内存需要多长时间 - 如果必须将内存分页到磁盘,则分配可能会非常昂贵。
因此预分配可能是个好主意,尤其是在使用复制垃圾收集器时。它会增加内存消耗,但分配速度很快,因为在大多数情况下它只是一个指针增量。
答案 5 :(得分:1)
正如人们所指出的那样 - GC的分配速度更快(因为它只是给你列表中的下一个块),但总体上更慢(因为它必须定期压缩堆,以便分配快速)。
所以 - 去寻求妥协解决方案(这实际上非常好):
你创建自己的堆,一个用于你通常分配的每个对象大小(或4字节,8字节,16字节,32字节等),然后,当你想要一块新的内存时,你就抓住了在适当的堆上最后'阻止'。因为你从这些堆中预先分配,所以你在分配时需要做的就是抓住下一个空闲块。这比标准分配器更好用,因为你很乐意浪费内存 - 如果你想分配12个字节,你将从16字节堆中放弃一个完整的16字节块。你保留了使用过的v free块的位图,这样你就可以快速分配,而不会浪费大量内存或需要压缩。
另外,因为你运行了几个堆,所以高度并行的系统工作得更好,因为你不需要经常锁定(即每个堆有多个锁,所以你几乎没有得到争用)
尝试一下 - 我们用它来代替非常密集的应用程序上的标准堆,性能上升了很多。
顺便说一句。标准分配器速度慢的原因是它们不会浪费内存 - 因此如果从标准堆中分配5字节,7字节和32字节,它将保留这些“边界”。下次您需要分配时,它会遍历那些寻找足够空间的人,以满足您的要求。这对于低内存系统来说效果很好,但是你只需看看大多数应用程序今天使用多少内存来看到GC系统走向另一个方向,并尝试尽可能快地进行分配,同时不关心内存是多少浪费了。
答案 6 :(得分:1)
问题有很多变量,但如果你的应用程序是用垃圾收集编写的, if if 你利用了{{3}的特殊功能},例如对不包含指针的块的不同分配调用,然后作为应用程序的一般规则 - 将具有更简单的接口 - 会跑得快一些 - 需要1.2倍至2倍的空间 而不是使用显式内存管理的类似应用程序。
对于支持这些声明的文档和证据,您可以看到有关Boehm网站的信息,以及Ben Zorn关于保守垃圾收集的测量成本的几篇论文。
最重要的是,您将节省大量精力,而不必担心会出现大量内存管理错误。
C vs C ++的问题是正交的,但GC肯定会比引用计数更快,特别是当没有编译器支持引用计数时。
答案 7 :(得分:0)
C和C ++都不会免费为您提供垃圾。他们会给你的是内存分配库(提供malloc / free等)。用于编写垃圾收集库的算法有许多在线资源。一个好的开始是link text
答案 8 :(得分:0)
大多数非GC语言将根据需要分配和取消分配内存,不再需要。 GC语言通常会预先分配大块内存,并且只在空闲时释放内存,而不是在密集任务的中间,所以如果GC在正确的时间启动,我将是 < / p>
D编程语言是垃圾收集语言,ABI与C兼容,部分ABI与C ++兼容。 This Page显示了C ++和D中字符串性能之间的一些基准。
答案 9 :(得分:0)
我建议如果你编写了一个程序,其中内存分配和释放(显式或GC)是瓶颈,那么你应该重新考虑你的架构,设计和实现。
答案 10 :(得分:0)
如果您不想显式管理内存,请不要使用C / C ++。有很多语言可以使用引用计数或编译器支持的垃圾收集器,它们可能会更好地为您工作。
C / C ++是在程序员管理自己的内存的环境中设计的。尝试改造GC或重新计算它们可能会有所帮助,但你会发现你要么必须牺牲GC的性能(因为它没有任何编译器暗示指针可能在哪里),或者你'找到新的和迷人的方法,你可以搞砸引用计数或GC或其他。
我知道这听起来不错,但实际上,你应该选择一种更适合这项任务的语言。