TCL 数组的最大大小
TCL max size of array
我在做一个工程应用,界面是用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
returns $i = 50.000.000 或多或少在 32 位上 Windows 7
解释起来有点复杂。 2GB 限制来自低级内存分配器,它有大小限制,因为它使用 signed 32 位整数来描述要分配多少内存。这在 32 位系统上很好,但它是一个开放的错误(可能是分配给我的)在 64 位系统上仍然如此; C API 中的正确类型实际上是 ssize_t
(是的,仍然有符号;负值用于信号)但是修复它会完全破坏很多 API,所以它需要一个主要的版本变更整理。
但是列表的最大大小是另外一回事。这从根本上与几件事的结合有关。首先,存在可以分配的内存结构的最大大小(2GB 限制),这意味着您可能无法可靠地在 64 位系统上的列表中获得超过 256M 的元素。然后是分配的项目总数,尽管这在实践中不是什么大问题,特别是如果您实际上多次将项目放入列表中(因为它们共享引用)。最后,还有列表的字符串表示的大小:如果你生成了很多,那么无论如何你做错了,但如果你正在创建它,那将是你的例子中真正的限制因素(因为那会尽快达到 2GB 限制)。
您达到内存限制的 实际 点可能会更低,具体取决于您的系统何时开始拒绝分配内存的请求。这完全取决于 OS,它倾向于根据系统上发生的其他事情做出决定,因此 难以置信地 很难在那里给出任何类型的通用规则。我的(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
非常快,但需要几秒钟。
我在做一个工程应用,界面是用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
returns $i = 50.000.000 或多或少在 32 位上 Windows 7
解释起来有点复杂。 2GB 限制来自低级内存分配器,它有大小限制,因为它使用 signed 32 位整数来描述要分配多少内存。这在 32 位系统上很好,但它是一个开放的错误(可能是分配给我的)在 64 位系统上仍然如此; C API 中的正确类型实际上是 ssize_t
(是的,仍然有符号;负值用于信号)但是修复它会完全破坏很多 API,所以它需要一个主要的版本变更整理。
但是列表的最大大小是另外一回事。这从根本上与几件事的结合有关。首先,存在可以分配的内存结构的最大大小(2GB 限制),这意味着您可能无法可靠地在 64 位系统上的列表中获得超过 256M 的元素。然后是分配的项目总数,尽管这在实践中不是什么大问题,特别是如果您实际上多次将项目放入列表中(因为它们共享引用)。最后,还有列表的字符串表示的大小:如果你生成了很多,那么无论如何你做错了,但如果你正在创建它,那将是你的例子中真正的限制因素(因为那会尽快达到 2GB 限制)。
您达到内存限制的 实际 点可能会更低,具体取决于您的系统何时开始拒绝分配内存的请求。这完全取决于 OS,它倾向于根据系统上发生的其他事情做出决定,因此 难以置信地 很难在那里给出任何类型的通用规则。我的(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
非常快,但需要几秒钟。