【问题标题】:Maximum Array of Strings VisualBasic WSH最大字符串数组 VisualBasic WSH
【发布时间】:2010-11-13 07:49:48
【问题描述】:

我正在 VB 中编写 WSH 脚本来读取通过 .Run 方法使用重定向目录列表生成的海量目录列表。

目录列表大约有8400行,但是每次运行脚本,都会出现以下循环

直到 DirList.AtEndOfStream Redim 保留 arrData(i) arrData(i) = DirList.ReadLine 我 = 我 + 1 循环

在 1800 到 3500 行的看似随机的范围内提前删除。这听起来像是数组大小问题还是 shell 内存限制?

我听说有人解析 LARGE 日志文件,像我一样一次读取它们。

【问题讨论】:

  • 代码示例中一起运行的行数是5行。除了开始和结束的控制结构行之外,肉包括redim、元素赋值、计数器迭代
  • 您可以在 Stack Overflow 上格式化您的代码,方法是选择它并单击上面带有 0 和 1 的按钮。这样,它将保留换行符,使其更易于阅读。此外,您没有提到当代码“提前中断”时会出现什么错误。这将为问题所在提供更多线索。

标签: arrays vbscript wsh


【解决方案1】:

在这种情况下,首先循环浏览文件并计算行数,然后将数组重新调整为所需的确切大小,这不是更好吗?然后关闭文件再次打开,这次你真的将行分配给数组元素了吗?

【讨论】:

    【解决方案2】:

    VBScript 中数组的大小受几个不同因素的限制,以先到者为准:

    • 最多 (2 ^ 31) - 1 个元素(因为元素的数量在内部存储为 Long 值,并且因为没有更大的数据类型可用作索引器)。

    • 最多 60 个维度。

    • 可用系统内存。

    然而,除了纯粹的理论练习之外,这些限制中的大多数都没有用,而且我会非常怀疑任何必须与它们相关的代码。

    因为您说您只有 8400 行要处理,所以我怀疑您是否遇到了对数组大小的理论限制。相反,您的代码最大的问题是您在循环中使用了Redim Preserve

    MSDN reference 解释说Redim Preserve 用于动态调整数组的最后一个维度,同时保留其现有内容。它不一定提到的是它是如何工作的。每次使用 Redim Preserve 时,都会使用您指定的元素数量创建一个新数组,并将前一个数组中元素的值复制到新数组中。这应该立即发出危险信号,因为这意味着在循环的每次迭代中,您都在为一个全新的数组分配空间并填充。您在循环中进行的迭代越多,问题就越严重,因为创建的每个新数组的大小都在逐渐增大。

    因此,您更有可能溢出了 VBScript 为局部变量分配的堆栈空间。 (有多合适——堆栈溢出错误?)最终,那些未使用的数组将被垃圾回收,但是当你在一个紧密的循环中执行此操作时,你会给内存和资源带来巨大的压力。

    您最好在数组中分配足够的空间来保存您需要保存的所有目录列表。您不一定要完全正确地获得最大尺寸。简单地分配比你需要的更多的东西仍然比不断地创建和销毁新阵列便宜得多。如果您仍然担心这还不够,您可以在循环中检查当前索引是否大于数组中元素的最大数量,如果是,则分配更多空间(例如,将其当前大小翻倍)。完成后,您可以使用Redim Preserve 命令释放多余的空间,同时保留好的数据,但这次只有一次!对于一个粗略的敲击示例:

    Dim MyData()                           ''#declare the array
    Dim MaxSize = 10000                    ''#guess an initial size
    Redim MyData(MaxSize)                  ''#allocate an array of the initial size
    
    Dim Size
    Do Until DirList.AtEndOfStream
        Size = Size + 1                    ''#record the current index
    
        If Size > MaxSize Then
            ''#The array is full, so allocate more space
            MaxSize = MaxSize * 2          ''#determine a new size (doubling is a good guess)
            Redim Preserve MyData(MaxSize) ''#add more space in the array
        End If
    
        MyData(Size) = DirList.ReadLine    ''#store this data in the array
    Loop
    
    If Size < MaxSize Then
        Redim Preserve MyData(Size)        ''#deallocate the extra space in your array
    End If
    

    这可能会使您的记忆免于滥用数组的常量分配和释放。

    【讨论】:

      【解决方案3】:

      在循环内使用 ReDim Preserve 是一种很好的做法。这是在 VBScript 中动态调整数组大小的唯一方法,Microsoft 自己的示例代码一直都在这样做。我个人已经很好地完成了数万次迭代,没有问题。

      您遇到的问题是系统资源不足。每次迭代都会分配一个新数组,同时释放旧数组。这个问题是名义上的,在大多数情况下完全可以忽略不计。

      您必须记住,您的脚本是在可执行环境中执行的。对于 WSH,这意味着您的所有操作都在单个线程中执行。 WSH 不提供任何管理脚本中内存使用的方法。

      我能给你的最好建议是限制迭代次数或分块读取输入文件(在每次迭代时释放它们)。如果没有看到导致错误的文件,或者没有收到您收到的实际错误消息,我无法提供任何更直接的建议。我只能说这种情况并不经常出现,而且几乎总是表明机器配置不佳或代码编写不佳。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多