Nim在内存效率方面是否类似于Java?

时间:2019-01-04 14:27:16

标签: nim

在64位Java中,每个对象实例都倾向于包含一个192-bit header,其中包含

  • 类指针
  • 标志和
  • 锁定(每个64位)。

这可能导致小对象占用大量内存。

尼姆的情况是否类似?用两种语言类似编写的大型应用程序(运行时大小可忽略不计)会使用大约相同的内存量吗?


更新

我进行了一些实验,其中我使用100M float64个元素构建了一个幼稚的单链接列表,并对其进行了多次迭代。

根据{{​​1}},

Java实际使用的内存比Nim低25%。

完整的Nim代码:

htop

这使用3.1GB,每个type Node = ref object data : float64 next : Node echo "Running" proc create(n : int): Node = var tmp = Node(data: 0, next: nil) for i in 1..<n: tmp = Node(data: i.float64, next: tmp) return tmp proc sum(x: Node): float64 = var tmp: float64 = 0 y = x while true: tmp += y.data y = y.next if y.isNil: return tmp proc sums(x: Node, n: int): float64 = var tmp: float64 = 0 for i in 0..<n: tmp += sum(x) / n.float64 return tmp let x = create(1000 * 1000 * 100) echo "Created" echo sums(x, 100) echo "Finished" 的输出为269位,而Java使用Node的非常相似的代码使用203位。这少于192位标头+ 128位结构。我猜想某种JIT优化可以使Java使用更少的内存来运行。

完整的Java代码:

Node

Node.java

public class Node { double data = 0; Node next = null; }

SListTest.java

2 个答案:

答案 0 :(得分:2)

在Nim中,您还可以将对象放入堆栈中,因此不需要垃圾回收,仅占用与对象中的成员一样多的空间。将自动分配的对象放在堆上时,存在一些垃圾回收内存开销,但对象本身仍保持其成员大小(当然还要加上填充)。

答案 1 :(得分:2)

对于Nim和HotSpot(请注意,并非所有Java实现都需要使用相同的方法),基本分配需要一个字表示GC信息,一个字表示类型信息(NimHotSpot) 。在HotSpot中,如果使用-XX:+UseCompressedOops不需要超过32GB的堆空间,则可以在64位计算机上将类型信息减少到半个字。

Java中的现代锁定实现不会产生额外的开销; GC字is also used for a thin locking scheme,并在需要时扩展为指向完整监视器的指针。因此,默认情况下,每个对象有两个开销字。

在您的示例中,在64位计算机上,Nim中每个对象的内存消耗为四个字:

  • 标头数据的两个单词。
  • 一个单词作为浮点值。
  • 一个单词代表下一个指针。

这种大小的1e8分配需要原始量32 * 1e8 = 3.2e9字节,即约3 GB。

我要补充一点,拥有很多小的分配往往bad for memory locality甚至不算那么多分配的成本,因此通常应尽可能避免。 (动态)数组几乎总是比链表更可取。