2012-02-05 151 views
2

我有一個加載DBI(DBD :: mysql),然後分叉子進程的守護進程。我想阻止分叉子進程中的DBI模塊在內存中。從子堆棧中刪除Perl模塊

因此,像這樣:

#!/usr/bin/perl 

use DBI; 
my $dbh = DBI->connect(db_info); 

my $pid = fork(); 
if($pid){ 

# The forked process here should not have DBI loaded 

} 

感謝您的幫助!

+1

你能解釋你爲什麼要這樣做嗎?這是一個非常奇怪的要求。 – 2012-02-05 04:13:05

+0

當然,我有一個服務器守護進程的子進程分叉。 chld進程不需要訪問DBI,但主進程確實是因爲它使用數據庫來加載可接受的對等主機IP列表。因此,在分離獨立進程以通過套接字進行通信之前,主線程驗證它是可接受的IP進行通信。 – GoldenNewby 2012-02-05 07:06:51

+0

你有證據證明DBI導致你有內存問題,或者這只是一種預感嗎? – 2012-02-05 14:21:23

回答

4

加載模塊就像腳本一樣執行它。 Perl模塊和腳本完全沒有區別。要卸載模塊,需要撤消運行它的效果。這不能機械地完成,而且手動執行也是不可行的。

最簡單的解決辦法是讓孩子exec有所東西。它甚至可能是你已經運行的腳本。

exec($^X, $0, '--child', @args) 

孩子可以通過它綁定到孩子的fd 0(標準輸入)和FD 1(標準輸出)有機會進入到插座。

+0

雖然這可以解決所述的問題,但值得注意的是,除非孩子很小,否則會耗費更多的時間和內存來「執行」一個新的Perl過程而不是創建一個分支。 – Schwern 2012-02-05 05:43:47

+0

@Schwern,你在說什麼?除非你做叉子,否則你不能'執行'。是的,它會佔用更多的內存,但實際上,OP不想與父母分享任何內容。 – ikegami 2012-02-05 05:46:46

+0

我指的是fork + exec而不是分叉。目前還不清楚OP爲什麼要做他們想問的問題。 – Schwern 2012-02-05 05:53:17

4

除非您在叉子後面放置負載,否則無法輕鬆完成此操作。但要做到這一點,你不得不使用use。代之以:

my $pid = fork(); 
if ($pid) { 
    # child 
} else { 
    require DBI; 
    import DBI; 
} 

這應該防止DBI模塊加載到fork之後。 use例程實質上是一個require/import,但在BEGIN {}塊內,這就是爲什麼你不必使用它。

+0

問題是主進程會根據需要產生子進程,而不是在一個固定的時刻在腳本中。 – GoldenNewby 2012-02-05 03:17:56

+0

您稱'import'爲間接對象方法?!?呸! – 2012-02-05 04:57:03

+0

@Joel Berger,它不像它是一個普通的方法調用(因爲你甚至可以調用它,即使這個包沒有'import'方法),而'import'被記錄在perlfunc中。雖然我通常會「y!!」在間接方法調用中,這是我沒有的。 – ikegami 2012-02-05 05:24:21

1

如果你正在運行一個現代Linux系統,那麼fork就是COW(寫時拷貝)。這意味着如果父母或孩子修改父母的頁面,則父母頁面只會複製到子女的地址空間。所以,DBI模塊不在分叉子進程的內存中。

Perl 5沒有任何方式從內存卸載模塊。如果由於某種原因,您真的需要孩子擁有與父代不同的代碼,那麼最好將代碼從主代碼中分離出來作爲自己的腳本,然後在分叉後使用exec運行子腳本。由於它必須編譯子代碼,所以這比正常的分叉要慢,所以如果你分叉了很多,最好有兩個腳本通過套接字互相交談並且具有「子」腳本預分叉。

+0

我不確定COW如何與Perl一起工作。 perl可執行文件可以是COW,因爲它不會被修改。編譯好的Perl代碼,包括加載的模塊,只是操作系統角度的數據。它不知道一些數據更改(變量)和一些數據*可能*不(代碼)。它只知道它已經分配了perl內存,perl試圖改變它的一部分。再說一次,我不是內存分配專家。 – Schwern 2012-02-05 05:47:49

+0

據我所知,lsof子進程可以複製所有內容,而不僅僅是它修改的東西。 – GoldenNewby 2012-02-05 07:35:30

+0

@Schwern COW是基於頁面的,所以除非Perl 5將Perl變量和代碼存儲在相同的頁面(我懷疑),否則所有的代碼都應該是COW安全的。 @GoldenNewby我不明白你如何使用'lsof'。據我所知'lsof'列出了打開的文件,而不是內存使用情況。子進程將具有父進程所有相同的文件句柄,但這對於內存使用情況沒有任何意義。 – 2012-02-05 14:18:54

1

現在知道你想用這個做什麼,因爲沒有一種好的方法來卸載模塊,Perl是一個很好的解決方案,用於編寫與應用服務器分開的認證服務器。應用程序服務器詢問認證服務器IP是否有權限。這樣他們仍然處於完全獨立的過程中。這可能也有安全優勢,您的應用程序代碼無法訪問您的身份驗證數據庫。

由於任何給定的應用程序可能會擴展到需要自己的SQL數據庫的地步,因此這個練習可能是徒勞的,但您的呼叫。

這是一堆額外的工作和維護和複雜性。只有當它給你帶來真正的記憶問題時,這纔是值得的,而不僅僅是因爲它是你的錯誤。記住,RAM非常便宜。開發人員時間非常昂貴。

+0

對於我正在開發的項目,RAM是我必須記住的。每個子進程(使用DBD :: mysql時)都使用了大約10MB的RAM。所以這意味着每100個進程就需要支付一筆RAM,每個進程大約20美分(租用一臺dedi服務器)。該項目保留了數千個這樣的連接,所以它實際上可以很快加起來。在刪除對MySQL的直接訪問之後,它將使用量減半。 – GoldenNewby 2012-02-06 00:57:12