ITコンサルの日常

ITコンサル会社に勤務する普通のITエンジニアの日常です。

一つのプロセスが開けるファイルの数はいくつ?(分からずじまい)

たのしいRuby第二版のp285

1つのプログラムが同時に開くことのできるファイルの数には制限があるので

との記述がありますが、じゃあ一体いくつなの?と思い調べてみることにしました。
で、こんなプログラムを書いてみました。

i = 1
while true
        open("openloop.rb")
        print("file opened ", i, "\n")
        i += 1
end

が、しかし、数万ファイルを開いてもエラーにならず。。
open後、ファイルハンドルを使っていないため、ガベージコレクト→自動的にクローズになっていると想像し、次のように書き換えました。

i = 1
ioarr = []
while true
        io = open("openloop.rb")
        ioarr << io
        print("file opened ", i, "\n")
        i += 1
end

すると見事に(?)エラーになりました。メッセージもそれっぽい。

...
file opened 2044
file opened 2045
openloop2.rb:4:in `initialize': Too many open files - openloop.rb (Errno::EMFILE
)
        from openloop2.rb:4:in `open'
        from openloop2.rb:4:in `<main>'

>

じゃあ、2045ってのが制限なのだと考えて、どうせOSの制限だろうと思い、レジストリエディタで該当データを探すも見つからず。。
発想を転換し、Javaでやったらどうなるの?と思い、次のようなコードを書いてみることに。

import java.io.*;
import java.util.*;

public class openloop
{
        public static void main(String[] args) throws Exception
        {
                List frlist = new ArrayList();
                int i = 1;
                while(true)
                {
                        FileReader fr = new FileReader("openloop.java");
                        frlist.add(fr);
                        System.out.println("file opened " + i);
                        i += 1;
                }
        }
}

これの結果はこう。

...
file opened 7821
file opened 7822
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.nio.HeapByteBuffer.<init>(Unknown Source)
        at java.nio.ByteBuffer.allocate(Unknown Source)
        at sun.nio.cs.StreamDecoder.<init>(Unknown Source)
        at sun.nio.cs.StreamDecoder.<init>(Unknown Source)
        at sun.nio.cs.StreamDecoder.forInputStreamReader(Unknown Source)
        at java.io.InputStreamReader.<init>(Unknown Source)
        at java.io.FileReader.<init>(Unknown Source)
        at openloop.main(openloop.java:12)

C:\work\rubyproject\funruby>

というわけで、ファイルオープンの上限に到達せず、メモリ不足でエラーになってしまいましたとさ。
ますますナゾ。
Googleで調べたところ、UNIXではulimit -aで表示される「open files」の値がそれっぽいのだそうです。

ulimit -aの実行例@cygwin
$ ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
open files                      (-n) 256
pipe size            (512 bytes, -p) 8
stack size              (kbytes, -s) 2034
cpu time               (seconds, -t) unlimited
max user processes              (-u) 63
virtual memory          (kbytes, -v) 2097152

だけど、Perlでopen filesを2048にしたのに、2045しか開けなかったって人がいますが。。
https://lists.sdsc.edu/pipermail/npaci-rocks-discussion/2006-November/022644.html
結局のところは不明です。
まあ、ちゃんとクローズしてれば、問題ないのでしょうけどね。ちゃんちゃん。