我正在开发一个工程应用程序,接口是用TCL TK编写的。
在我需要使用(非常)大型阵列之前,一切都很顺利。 370.000.000个元素,每个元素长度为2到10个字符(线性增长)。
我的问题是,¿TCL阵列的大小限制在哪里? 我一直在阅读和调查,我发现只有“2GB”的字符串数据,但我不知道它是否可靠,因为它没有解释原因。
我做了一个实验:
set lista [list ]
catch {
for {set i 0} {$i < 370000000} {incr i} {
lappend lista $i
}
}
puts $i
在32位Windows 7上返回$ i = 50.000.000或更少
答案 0 :(得分:10)
解释起来有点复杂。 2GB限制来自低级别内存分配器,它具有大小限制,因为它使用签名 32位整数来描述要分配的内存量。在32位系统上这很好,但它是一个开放的bug(可能会分配给我),它在64位系统上仍然是正确的; C API中的正确类型实际上是ssize_t
(是的,仍然是签名的;负值用于信令)但修复它完全破坏了很多API,因此需要对主要版本进行更改才能进行整理。
但是列表的最大大小是另外的。这基本上与一些事物的组合有关。首先,可以分配的内存结构的最大大小(2GB限制),这意味着您可能无法在64位系统的列表中可靠地获得超过256M的元素。然后是分配的项目总数,尽管在实践中这不是一个问题,特别是如果你实际上多次将项目放在列表中(因为它们共享引用)。最后,列表中字符串表示的大小:如果你经常产生那么多,那么你无论如何都做错了,但如果你的例子中存在错误,那么这将是你的例子中的真正限制因素。你正在创建它(因为它会更快达到2GB的限制)。
您达到内存限制的实际点可能会更低,具体取决于系统何时开始拒绝分配内存的请求。这完全取决于操作系统,操作系统倾向于根据系统上发生的其他事情做出决定,因此,难以置信难以在那里提供任何一般规则。我的(64位,OSX)系统需要很长时间,但成功运行了示例代码:
$ tclsh8.6
% eval {
set lista [list ]
catch {
for {set i 0} {$i < 370000000} {incr i} {
lappend lista $i
}
}
puts $i
}
370000000
% llength $lista
370000000
% unset lista
% exit
llength
是唯一真正快速的操作(因为它可以从列表元数据中拉出长度)。 unset
需要很长时间。 exit
很快,但花了几秒钟。