linux 句柄相關知識

句柄的介紹及應用
句柄是在 Windows 中引入的一個概念,它是和對象一一對應的 32 位無符號整數值。句柄可以映射到唯一的對象,它是處理對象的一個接口,對於所涉及的對象,可以通過相應的句柄來操作它。句柄的引入主要是操作系統爲了避免應用程序直接對某個對象的數據結構進行操作爲目的,用操作句柄來代替操作對象。

在 Linux 環境中,任何事物都是用文件來表示,設備是文件,目錄是文件,socket 也是文件。用來表示所處理對象的接口和唯一接口就是文件。應用程序在讀 / 寫一個文件時,首先需要打開這個文件,打開的過程其實質就是在進程與文件之間建立起連接,句柄的作用就是唯一標識此連接。此後對文件的讀 / 寫時,目標文件就由這個句柄作爲代表。最後關閉文件其實就是釋放這個句柄的過程,使得進程與文件之間的連接斷開。

查看當前進程打開了多少句柄數

  lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|more

#第一列是打開的句柄數,第二列是進程ID

1>執行 ps -ef | grep 進程名稱
2>執行 ls -l /proc/進程ID/fd | wc -l ,查看句柄數量

查看系統級別的能夠打開的文件句柄的數量

  # cat /proc/sys/fs/file-max

#查看top 10 進程句柄數

lsof -n|awk '{print $2}'|sort | uniq -c|sort -nr | head -n 10

句柄泄露
造成句柄泄露的主要原因,是進程在調用系統文件之後,沒有釋放已經打開的文件句柄。在 Linux 系統中,進程與文件之間是通過“打開文件”操作建立連接,文件系統會返回文件句柄來唯一標識進程與文件的連接。每當一個進程執行完畢之後,Linux 系統會將與進程相關的文件句柄自動釋放。但是,如果進程一直處於執行狀態,文件的句柄只能通過“關閉文件”操作來自我釋放。與 Windows 系統的設置不同,Linux 系統對進程可以調用的文件句柄數做了限制,在默認情況下,每個進程可以調用的最大句柄數爲 1024 個。超過了這個數值,進程則無法獲得新的句柄。因此,句柄的泄露將會對進程的功能失效造成極大的隱患。

如何修改系統最大句柄數
Linux 中,單個進程能夠打開的最大文件句柄數量是可以配置的,系統默認是 1024。當單個進程打開的文件句柄數量超過了系統定義的值,就會出現“Too many files open”的錯誤提示。用戶可以通過以下命令查看系統定義的最大值:

ulimit – n

查看當前進程打開了多少句柄數:

# lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|more

131 24204 

57 24244 

其中第一列是打開的句柄數,第二列是進程ID。可以根據ID號來查看進程名:

# ps aef|grep 24204

nginx  24204 24162 99 16:15 ?    00:24:25 /usr/local/nginx/sbin/nginx -s

對於一般的應用程序而言 1024 已經完全夠用了,但是有些進程處理大量請求,很有可能 1024 就不夠用了,則需要調整系統參數,來適應應用的變化。Linux 有硬性和軟性設置兩種,都可以通過 ulimit 來設置。例如

ulimit – HSn 2048
以上命令就可以設置 H(硬性),S(軟性)的值爲 2048。n表示設定單個進程最大的打開文件句柄數量。個人覺得最好不要超過4096,畢竟打開的文件句柄數越多響應時間肯定會越慢。設定句柄數量後,系統重啓後,又會恢復默認值。如果想永久保存下來,可以修改.bash_profile文件,可以修改 /etc/profile 把上面命令加到最後。

Linux 檢測句柄的方法
在 Linux 平臺上,lsof(list open files)是一個列出當前系統打開文件的工具。在 Linux 環境下,任何事物都以文件的形式存在,系統在後臺爲應用程序分配了一個文件描述符,無論這個文件的本質如何,該文件描述符爲應用程序與基礎操作系統之間的交互提供了通用接口。因爲應用程序打開文件的描述符列表提供了大量關於這個應用程序本身的信息,因此通過 lsof 工具能夠查看這個列表對系統監測以及排錯將是很有幫助的。

在終端下輸入 lsof 即可顯示系統打開的文件,因爲 lsof 需要訪問核心內存和各種文件,所以必須以 root 用戶的身份運行它才能夠充分地發揮其功能。屏幕顯示如下:

COMMAND     PID    USER   FD      TYPE     DEVICE      SIZE       NODE NAME 
 init          1    root  cwd       DIR        3,2      4096          2 / 
 init          1    root  rtd       DIR        3,2      4096          2 / 
 init          1    root  txt       REG        3,2     32684    1200637 /sbin/init 
……

lsof 輸出各列信息的意義如下:

COMMAND:進程的名稱
PID:進程標識符
USER:進程所有者
FD:文件描述符,應用程序通過文件描述符識別該文件。如 cwd、txt 等 TYPE:文件類型,如 DIR、REG 等
DEVICE:指定磁盤的名稱
SIZE:文件的大小
NODE:索引節點(文件在磁盤上的標識)
NAME:打開文件的確切名稱

在 Linux 系統中可以用 man lsof 查看詳細的介紹和參數使用方法,在這裏不作過多介紹。在偵測程序句柄泄露的應用中,我們主要用到 lsof 的如下使用方法:

lsof – p PID

PID 是指我們要偵測程序的進程號,可以用命令 ps – ef 來得到。我們以進程號 14946 爲例:

# lsof -p 14946 
 COMMAND     PID USER   FD   TYPE  DEVICE     SIZE   NODE NAME 
 rpc.rquot 14946 root  cwd    DIR     3,2     4096      2 / 
 rpc.rquot 14946 root  rtd    DIR     3,2     4096      2 / 
 rpc.rquot 14946 root txt REG 3,2 65292 267543 
 /usr/sbin/rpc.rquotad 
 rpc.rquot 14946 root mem REG 3,2 45889 535442 
 /lib/libnss_files-2.3.4.so 
 rpc.rquot 14946 root mem REG 3,2 1454802 541622 /lib/tls/ 
 libc-2.3.4.so 
……

每一行就代表該進程正在使用的一個文件,即句柄。統計行數總和就是該進程打開的所有句柄數量,這爲我們用統計方法偵測句柄泄露提供的依據。

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