PHP session垃圾回收機(jī)制

概述

由于PHP的工作機(jī)制,它并沒有一個(gè)daemon線程,來定時(shí)地掃描session信息并判斷其是否失效。當(dāng)一個(gè)有效請(qǐng)求發(fā)生時(shí),PHP會(huì)根據(jù)全局變量 session.gc_probability/session.gc_divisor(同樣可以通過php.ini或者ini_set()函數(shù)來修改) 的值,來決定是否啟動(dòng)一個(gè)GC(Garbage Collector)。默認(rèn)情況下,session.gc_probability = 1,session.gc_divisor =100,也就是說有1%的可能性會(huì)啟動(dòng)GC。GC的工作,就是掃描所有的session信息, 用當(dāng)前時(shí)間減去session的最后修改時(shí)間(modified date),同session.gc_maxlifetime參數(shù)進(jìn)行比較,如果生存時(shí)間已經(jīng)超過gc_maxlifetime,就把該session刪 除。

gc_maxlifetime無效

那為什么會(huì)發(fā)生gc_maxlifetime無效的情況呢?

  1. 在默認(rèn)情況下,session信息會(huì)以文本文件的形式,被保存在系統(tǒng) 的臨時(shí)文件目錄中。在Linux下,這一路徑通常為\tmp,在Windows下通常為C:\Windows\Temp。當(dāng)服務(wù)器上有多個(gè)PHP應(yīng)用時(shí), 它們會(huì)把自己的session文件都保存在同一個(gè)目錄中。同樣地,這些PHP應(yīng)用也會(huì)按一定機(jī)率啟動(dòng)GC,掃描所有的session文件。問 題在于,GC在工作時(shí),并不會(huì)區(qū)分不同站點(diǎn)的session。舉例言之,站點(diǎn)A的gc_maxlifetime設(shè)置為2小時(shí),站點(diǎn)B的 gc_maxlifetime設(shè)置為默認(rèn)的24分鐘。當(dāng)站點(diǎn)B的GC啟動(dòng)時(shí),它會(huì)掃描公用的臨時(shí)文件目錄,把所有超過24分鐘的session文件全部刪 除掉,而不管它們來自于站點(diǎn)A或B。這樣,站點(diǎn)A的gc_maxlifetime設(shè)置就形同虛設(shè)了。找到問題所在,解決起來就很簡(jiǎn)單了。修改session.save_path參數(shù),或者使用session_save_path()函數(shù),把保存session的目錄指向一個(gè)專用的目錄,gc_maxlifetime參數(shù)工作正常了。

  2. 還有一個(gè)問題就是,gc_maxlifetime只能保證session生存的最短時(shí)間,并不能夠保存在超過這一時(shí)間之后session信息立即會(huì)得到 刪除。因?yàn)镚C是按機(jī)率啟動(dòng)的,可能在某一個(gè)長(zhǎng)時(shí)間內(nèi)都沒有被啟動(dòng),那么大量的session在超過gc_maxlifetime以后仍然會(huì)有效。解決這 個(gè)問題的一個(gè)方法是,把session.gc_probability/session.gc_divisor的機(jī)率提高,如果提到100%,就會(huì)徹底解 決這個(gè)問題,但顯然會(huì)對(duì)性能造成嚴(yán)重的影響。另一個(gè)方法是自己在代碼中判斷當(dāng)前session的生存時(shí)間,如果超出了gc_maxlifetime,就清 空當(dāng)前session。

gc工作原理

php session GC功能,就是Garbage Collector。這個(gè)GC啟動(dòng)的時(shí)候,會(huì)清除那些已經(jīng)“超時(shí)”的session。它的工作原理是這樣的:

  1. 用戶訪問并登陸網(wǎng)站,這時(shí)候后臺(tái)會(huì)調(diào)用session_start來嘗試生成一個(gè)會(huì)話(如果已經(jīng)有會(huì)話,則相當(dāng)于一次有效會(huì)話請(qǐng)求)
  2. 對(duì)于這樣的每一次有效會(huì)話請(qǐng)求(Request),apache的php模塊會(huì)根據(jù)session相關(guān)的全局變量gc_probability/gc_divisor =>計(jì)算出啟動(dòng)GC的概率,并由此概率來決定在這次請(qǐng)求中是否應(yīng)該啟動(dòng)GC。舉例來說,session.gc_probability的缺省值為1,session.gc_divisor的缺省值為100,則啟動(dòng)“垃圾回收”器的概率是1%,這就意味著在每100次請(qǐng)求中,會(huì)有可能清理一次過期會(huì)話
  3. 如果GC啟動(dòng),則GC會(huì)掃描當(dāng)前會(huì)話所在路徑(session.save_path)下的所有會(huì)話文件,并根據(jù)另外一個(gè)全局變量session.gc_maxlifetime的多少來判斷哪些session已經(jīng)過期(“當(dāng)前時(shí)間”與“會(huì)話文件的atime或者mtime”之間的差大于gc_maxlifetime:過期),并刪除這些過期的session
  4. 如果你在一個(gè)session啟動(dòng)后,長(zhǎng)時(shí)間沒有任何交互操作(譬如,不停地碼字,沒有提交或者保存為草稿),那么你的保存在后臺(tái)的會(huì)話文件將得不到機(jī)會(huì)被修改或者訪問,在gc_maxlifetime(缺省值1440秒=24分鐘)時(shí)間后,它有可能因失效而被清理,這以后你再提交,就會(huì)因?yàn)闀?huì)話失效而報(bào)錯(cuò)

理解

  1. session_id保存在瀏覽器(客戶端)的cookie中,關(guān)閉瀏覽器保存sessiond_id的cookie失效,這時(shí)候無法訪問原來session文件。服務(wù)器端session文件可能存在,還未刪除。
  2. 當(dāng)一個(gè)用戶,24分鐘沒有任何操作(向服務(wù)器發(fā)送請(qǐng)求,瀏覽器打開著),session文件可能被gc垃圾回收了,24分鐘后訪問,將創(chuàng)建跟原session_id相同的session新文件,此時(shí)原有的session文件內(nèi)容將不存在了。
  3. 自動(dòng)登錄,不是設(shè)置session_id的cookie的有效時(shí)間,是在瀏覽器端保存包含登錄信息(如用戶名,密碼)的cookie。
  4. 一個(gè)session_id的作用時(shí)間 到 瀏覽器關(guān)閉結(jié)束,再次打開瀏覽器,是生成了新的session_id(新的session文件)。
  5. 在服務(wù)器端判斷session文件是否無效(刪除),當(dāng)前時(shí)間-文件修改時(shí)間 > gc_maxlifetime,此時(shí)失效。
  6. 每次腳本執(zhí)行,都修改文件修改時(shí)間

原文

http://blog.csdn.net/21aspnet/article/details/7218923

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容