TCL中数组的最大尺寸是多少?

5

我正在处理一个工程应用程序,其界面是用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左右。

1个回答

10

解释起来有点复杂。2GB的限制来自于低级别的内存分配器,由于使用了带符号的32位整数来描述要分配多少内存的大小限制。在32位系统上这没问题,但它仍然适用于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 相当快,但需要几秒钟。


2
很高兴直接从深入系统的专家那里得到答案。 - glenn jackman
1
感谢@donal-fellows先生,我已经使用TCL作为我的主要编程语言已经有5年了,但仍有很多需要学习的地方。 - JGInternational
1
我已经使用它20年了,但我仍然不知道所有的东西。 :-) - Donal Fellows

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接