什么是句柄
句柄就是一個對象的標識符,只要獲得對象的句柄业汰,我們就可以對對象進行任意的操作伙窃,包括窗口,按鈕样漆,圖標为障,輸出設備,控件或者文件等放祟;
句柄是一種特殊的智能指針鳍怨,用一個唯一的整數(shù)值標識一個對象(即編號),并不指向?qū)嶋H的內(nèi)核對象跪妥,而是內(nèi)核對象的虛擬地址鞋喇;
只有Windows中才有句柄,Windows中的句柄是指針的指針眉撵,因為windows中對象的經(jīng)常會在內(nèi)存中移動侦香,所以地址值經(jīng)常會變,所以就對外提供一個指針的指針即句柄給用戶纽疟,句柄的地址是不會變的罐韩。
Linux中是沒有文件句柄的,只有文件描述符污朽,只是大家習慣把它說成句柄伴逸,Linux中, 每當進程打開一個文件時膘壶,系統(tǒng)就為其分配一個唯一對應的整型文件描述符错蝴,用來標識這個文件;
Windows之所以要設立句柄颓芭,根本上源于內(nèi)存管理機制的問題—虛擬地址顷锰,簡而言之數(shù)據(jù)的地址需要變動,變動以后就需要有人來記錄管理變動亡问,(就好像戶籍管理一樣)官紫,因此系統(tǒng)用句柄來記載數(shù)據(jù)地址的變更肛宋。
Windows系統(tǒng)中有許多內(nèi)核對象(這里的對象不完全等價于"面向?qū)ο蟪绦蛟O計"一詞中的"對象",雖然實質(zhì)上還真差不多)束世,比如打開的文件酝陈,創(chuàng)建的線程,程序的窗口毁涉,等等沉帮。這些重要的對象肯定不是4個字節(jié)或者8個字節(jié)足以完全描述的,他們擁有大量的屬性贫堰。為了保存這樣一個"對象"的狀態(tài)穆壕,往往需要上百甚至上千字節(jié)的內(nèi)存空間,那么怎么在程序間或程序內(nèi)部的子過程(函數(shù))之間傳遞這些數(shù)據(jù)呢其屏?拖著這成百上千的字節(jié)拷貝來拷貝去嗎喇勋?顯然會浪費效率。那么怎么辦偎行?當然傳遞這些對象的首地址是一個辦法年叮,但這至少有兩個缺點:
暴露了內(nèi)核對象本身烹俗,使得程序(而不是操作系統(tǒng)內(nèi)核)也可以任意地修改對象地內(nèi)部狀態(tài)(首地址都知道了烁落,還有什么不能改的掠械?),這顯然是操作系統(tǒng)內(nèi)核所不允許的汗盘;
操作系統(tǒng)有定期整理內(nèi)存的責任皱碘,內(nèi)存管理器經(jīng)常在內(nèi)存中來回移動對象,依此來滿足各種應用程序的內(nèi)存需要隐孽,對象被移動意味著它的地址變化了癌椿,如果地址總是如此變化,我們該到哪里去找該對象呢??
所以菱阵,Windows操作系統(tǒng)就采用進一步的間接:在進程的地址空間中設一張表踢俄,表里頭專門保存一些編號和由這個編號對應一個地址,而由那個地址去引用實際的對象晴及,這個編號跟那個地址在數(shù)值上沒有任何規(guī)律性的聯(lián)系都办,純粹是個映射而已。這個編號就叫做"句柄"虑稼。
關于Windows句柄
Windows對象和句柄類型
Windows對象分為內(nèi)核對象琳钉、GDI對象和User對象:
內(nèi)核對象是不屬于進程的,是屬于windows內(nèi)核的蛛倦。進程只有一個內(nèi)核對象句柄表歌懒,用來存放所有的內(nèi)核對象句柄。所以溯壶,多個進程可以同時使用一個內(nèi)核對象 及皂,只要有句柄即可甫男。
對于GDI對象和User對象,他們是一個進程內(nèi)部擁有的東西验烧,不會被多個進程共有板驳。GDI對象與繪圖相關,而User對象與交互相關碍拆。
內(nèi)核對象如文件若治、進程、線程等倔监;GDI對象如字體、畫筆菌仁、位圖等浩习;User對象如圖標、菜單济丘、窗體等谱秽,不同對象對應著不同類型的句柄,如文件句柄摹迷、窗體句柄等疟赊;
查看句柄
通過任務管理器
通過Process Explorer工具,點擊進程右鍵峡碉、屬性近哟、性能選項卡查看:
Handles為內(nèi)核對像的句柄,包括文件句柄鲫寄,GDI 和User分別是GDI句柄和User句柄吉执。
修改句柄
文件句柄數(shù)默認為512,GDI句柄默認為10000地来,User句柄默認為10000戳玫;
GDI和User句柄可通過注冊表修改,修改“GDIProcessHandleQuota”與“USERProcessHandleQuota”注冊表項:
關于Linux句柄
Linux中類似Windowns句柄的是fd未斑,在Linux系統(tǒng)設計里面遵循一切都是文件的原則咕宿,即磁盤文件、目錄蜡秽、網(wǎng)絡套接字府阀、磁盤、管道等芽突,所有這些都是文件肌似,在我們進行打開的時候會返回一個fd,即是文件句柄诉瓦,Linux不存在具體的句柄類型川队。
查看句柄
ulimit?-n:查看當前用戶單個進程能夠打開的最大文件句柄數(shù)量(包括Socket鏈接)力细,默認是1024;
lsof -n?|awk?'{print?$2}'|sort|uniq?-c?|sort?-nr|more:查看所有進程的句柄數(shù)量(降序排序)固额,第一列是句柄數(shù)眠蚂,第二列是PID;
lsof?-n|awk?'{print?$2}'|sort|uniq?-c|sort?-nr|more?|grep <pid>:查看某個進程的句柄數(shù)斗躏;
修改句柄
方法1:ulimit?-HSn?4096:修改句柄數(shù)為4096逝慧,僅對當前進程有效,關閉或重啟失效啄糙;
方法2:修改linux系統(tǒng)參數(shù)笛臣。vi /etc/security/limits.conf 添加
* soft nofile 2048
* hard nofile 32768?
就可以將文件句柄限制統(tǒng)一改成軟2048,硬32768隧饼,硬限制是實際的限制沈堡,而軟限制,是warnning限制燕雁,只會做出warning 诞丽;
修改以后保存,注銷當前用戶拐格,重新登錄僧免,執(zhí)行ulimit -a 查看當前狀態(tài)是否生效。
句柄問題
1. 句柄泄露:句柄只增不減捏浊,一般是由于各類資源未釋放懂衩,如Socket、文件等金踪;
2.?too many files open:這里的file不只是指文件勃痴,包括Socket連接等,當句柄數(shù)超過了限制热康,進程將無法獲取新的句柄沛申,而從導致不能打開新的文件或者網(wǎng)絡套接字,對于線上Server即會出現(xiàn)服務被拒絕的情況姐军;