我最近继承了其他人写过的一些代码。
我发现代码中的每个地方都打开了一个目录,但它从未关闭,因为原始开发人员有语法问题 - 他使用close
函数尝试关闭目录句柄而不是closedir
函数。
代码是这样的:
opendir( DIR, $dir ) or die "Cannot open $dir: $!\n";
@files = readdir( DIR );
close( DIR );
(这是Perl最佳实践(第208,278页)关于检查close
函数返回的另一个好处。如果在这种情况下检查close
的返回,它会没有“错误的文件编号”。)
我已经将此更改为closedir
,但它让我开始疑惑:由于目录句柄从未关闭,对于保持目录句柄长时间打开有什么负面影响?
此程序较大(3,500行代码),运行一段时间(5-10分钟),并且该程序的多个实例同时运行。对于上面示例中的此目录,$dir
对于所有实例都是相同的值。如果此程序的10个实例同时运行,则它们都持有针对同一目录的打开目录句柄5分钟或更长时间。我确信Perl会在程序结束时自动关闭目录句柄,但最佳做法是尽快关闭它。
对我来说更明显的是,打开文件句柄会导致问题(特别是对于可以写入的文件句柄),但是如果不关闭目录句柄会发生什么坏事?
我问的原因是因为有一个奇怪的情况,这个程序试图创建一个文件(在上面的$ dir定义的目录中)。文件名中嵌入了PID,因此文件可能已存在的可能性较小,但Perl无法打开文件进行写入,因为它说它已经存在。当我们查看目录时,该文件不存在。我想知道这个目录下的所有打开目录句柄是否都会导致这样的问题?
我不确定操作系统是否有所作为,但该程序在AIX上运行。
提前致谢,周五快乐!
答案 0 :(得分:11)
你浪费了一个目录描述符 - 它可能被视为文件描述符。如果您的程序打开了足够的目录以用完文件描述符,那么最终会对您造成伤害。否则,它是非常无害的,虽然不太理想。它使系统(和Perl)保留了它本可以释放的资源。
如果目录句柄是局部变量,而不是普通的DIR样式名称,那么您可能会在后面清理Perl。请参阅opendir,其中包含:
打开一个名为EXPR的目录,供readdir,telldir,seekdir,rewinddir和closedir处理。如果成功则返回true。 DIRHANDLE可以是一个表达式,其值可以用作间接dirhandle,通常是真正的dirhandle名称。如果DIRHANDLE是未定义的标量变量(或数组或散列元素),则会为变量分配对新匿名目标的引用。 DIRHANDLEs有自己的命名空间,与FILEHANDLEs分开。
答案 1 :(得分:8)
不会有任何严重后果。内核本身的内存使用量会略有增加,内核本身无法释放内部使用的迭代器来遍历目录条目列表,也可能来自perl端。
另外,只要目录的任何描述符仍然打开,就无法从文件系统中实际删除数据。如果某个其他外部进程将删除您拥有句柄的目录,它将停止出现在将来的目录列表中,但数据仍然必须保留在磁盘上,并且仍然可以通过打开的句柄进程访问。例如,这可能导致磁盘使用中的奇数。
另请注意,您不一定要手动关闭所有手柄。使用词法文件句柄时,只要最后一次对句柄的引用消失,就会自动关闭:
{ # new scope
opendir(my $handle, ...) or ...;
...
} # implicit closedir happens here
答案 2 :(得分:7)
这是一个总是使用词法文件(和目录)句柄的课程 - 词法句柄在超出范围时会自动关闭。
所以你只是浪费描述符(正如Jonathan所描述的),如果1.你使用了旧式的glob句柄,或者2.所有代码都在一个没有子程序或其他作用域的平面脚本中。使用良好的编程实践,无意中的错误会更少:)