in reply to old file descriptors not being cleaned up

It would appear that the issue is you are opening them all before closing any of them. If you want file descriptors to stay under your ulimit, you really want to close some of them before opening others.

If you're counting on the filehandles to close from going out of scope, there's some news you might not want. They won't because you have put them in an array. Try reusing the same lexical scalar over and over instead for the file handle if you want that, or manually close your file handles.

You can read data from the files, close the files, and still keep the data around. There's no need for all those files to be open at once.

As examples, the first of these bombs out for too many open file handles, while the second and third will just keep running:

my $data, $i, @file; while ( 1 ) { open $file[ $i ], '<', '/dev/zero' or die "Cannot read: $!\n"; read $file[ $i ], $data, 4; $i++; print "$data\t$i iterations...\n" unless $i % 100; }
my $data, $i; while ( 1 ) { open my $file, '<', '/dev/zero' or die "Cannot read: $!\n"; read $file, $data, 4; close $file; $i++; print "$data\t$i iterations...\n" unless $i % 100; }
my $data, $i, @file; while ( 1 ) { open $file[ $i ], '<', '/dev/zero' or die "Cannot read: $!\n"; read $file[ $i ], $data, 4; close $file[ $i ]; $i++; print "$data\t$i iterations...\n" unless $i % 100; }