设置DFS副本时的一个常见任务是确定已复制文件夹中32个最大文件的大小 - 根据当前的最佳实践,这些文件的总和应该是暂存区域的最小大小。
在Technet博客中提供了查找和计算此前32个文件大小的方法:https://blogs.technet.microsoft.com/askds/2011/07/13/how-to-determine-the-minimum-staging-area-dfsr-needs-for-a-replicated-folder/
它依赖于使用Get-ChildItem
在路径中查找所有文件及其大小,按大小排序,丢弃除32位之外的所有文件,然后计算总和。
当您的路径中包含有限数量的文件时,这很好,但在索引具有数十万(甚至数百万个文件)的文件夹时存在严重缺陷。该进程在执行时将所有内容转储到内存中 - 在我的示例中,它消耗超过2GB的虚拟内存 - 并且需要很长时间,即使单个文件非常小。在PS实例关闭之前,内存将保持分配状态。
PS C:\> measure-command { (get-childitem F:\Folder\with\966693\items -recurse |
sort-object length -descending | select-object -first 32 |
measure-object -property length -sum).sum }
Days : 0
Hours : 0
Minutes : 6
Seconds : 6
Milliseconds : 641
Ticks : 3666410633
TotalDays : 0.00424353082523148
TotalHours : 0.101844739805556
TotalMinutes : 6.11068438833333
TotalSeconds : 366.6410633
TotalMilliseconds : 366641.0633
答案 0 :(得分:1)
如果您可以加快Get-ChildItem
的速度,我会感到惊讶,除非您可以避免为每个文件构建[IO.FileInfo]
个对象(.Net DirectorySearcher可能?)。
但是你可以通过不保留所有结果来减少内存需求,在这个例子中只保留正在进行的N最大值100,但是可以调整到测试内存/性能,例如。
$BufferSize = 100
$FileSizes = New-Object System.Collections.ArrayList
Get-ChildItem 'd:\downloads' -Force -Recurse -File | ForEach {
$null = $FileSizes.Add($_.Length)
if ($FileSizes.Count -gt $BufferSize)
{
$FileSizes.Sort()
$FileSizes.RemoveRange(0, ($BufferSize-32))
}
}
($FileSizes[0..31] | measure-object -Sum).Sum/1GB
在某些最大的文件被隐藏的情况下,向gci添加了-Force
参数。
答案 1 :(得分:0)
稍微调整 - 实例化System.Collections.ArrayList
以存储文件长度列表 - 在同一目录上执行查询的时间几乎减半。在您向其中添加新项目时,您需要not constantly creating/destroying a standard fixed-sized array。
此样本的Powershell进程的内存使用量仍低于900MB。如果我想重用PS控制台,我也喜欢将变量设置为$ null。
measure command { $total = New-Object System.Collections.ArrayList;
gci F:\Folder\with\966693\items -file -r |
ForEach { $total.Add($_.length)>$null } ;
(($total | sort -descending | select -first 32 |measure-object -sum).sum/1GB) }
Days : 0
Hours : 0
Minutes : 3
Seconds : 34
Milliseconds : 215
Ticks : 2142159038
TotalDays : 0.00247935073842593
TotalHours : 0.0595044177222222
TotalMinutes : 3.57026506333333
TotalSeconds : 214.2159038
TotalMilliseconds : 214215.9038
Tidier多线版:
$total = New-Object System.Collections.ArrayList
gci F:\Folder\with\966693\items -file -r | ForEach { $total.Add($_.length)>$null }
($total | sort -descending | select -first 32 | measure-object -sum).sum/1GB