[Java] Socket報錯打開文件過多

Caused by: java.net.SocketException: Too many open files

        at sun.nio.ch.Net.socket0(Native Method)

        at sun.nio.ch.Net.serverSocket(Net.java:415)

        at sun.nio.ch.ServerSocketChannelImpl.<init>(ServerSocketChannelImpl.java:88)

        at sun.nio.ch.SelectorProviderImpl.openServerSocketChannel(SelectorProviderImpl.java:56)

        at java.nio.channels.ServerSocketChannel.open(ServerSocketChannel.java:108)

 

原因有多種,網上有說是因爲系統允許打開的默認文件數設置太小,對於網絡訪問,高併發訪問的情況,只需修改系統參數即可解決,先查看當前的設置:

$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 256
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1418
virtual memory          (kbytes, -v) unlimited

可以看出,對於我的個人電腦來說“open files”的設置是256。

可通過命名-n選項進行修改

ulimit -n 4096

但該選項有個問題,就是隻是臨時生效,比如重啓電腦後將失效,爲了保證始終有效,有的linux系統通過修改limits.conf文件設置:

* soft nofile 65535
* hard nofile 65535

通過修改/etc/security/limits.conf文件,把所有用戶的進程打開文件上限改爲65536。

其中,*表示所有用戶,soft/hard表示軟/硬限制,還可以只真對某個用戶或某個組做修改,具體方法參見文件註釋。修改後需要重新啓動系統才能生效。

 

但是有時候,不是單靠修改該參數就能解決問題,有的是因爲程序的問題,比如本人曾經遇到過一個程序任務,由於連接服務器失敗,有個策略設置了失敗嘗試,但是未對嘗試次數進行限制,導致每過一秒就嘗試連接socket,結果很快就導致系統掛掉,拋出此錯誤。其他程序只要讀寫文件均無法完成,比如:

java.net.SocketException: Too many open files (Accept failed)
    at java.net.PlainSocketImpl.socketAccept(Native Method)
    at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
    at java.net.ServerSocket.implAccept(ServerSocket.java:545)
    at java.net.ServerSocket.accept(ServerSocket.java:513)

Caused by: java.io.FileNotFoundException: /tmp/data_xxxxxx.dat (Too many open files)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(FileInputStream.java:195)
    at java.io.FileInputStream.<init>(FileInputStream.java:138)

甚至還出現過內存溢出的錯誤:

out of disk space or the JVM running out of memory

 

爲了解決此類問題,如果已經定位了某個程序的問題,可通過該程序的日誌進行分析,也可以通過命令查看某個線程是否打開了過多文件句柄,首先通過關鍵字查詢線程ID,不然java線程:

ps -ef | grep java

然後執行通過線程ID查看線程所打開的文件列表:

lsof -p 1902 

 也可先統計有多少文件被打開

lsof -p 1902 | wc -l

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章