2009-09-15 81 views
35

在我目前工作的一個系統中,存在加載大量的數據到一個數組進行排序/聚集/不管一個進程。我知道這個過程需要優化內存使用,但在短期內它只需要工作。增加PHP memory_limit。它在什麼時候變得瘋狂?

鑑於數據加載到陣列的數量,我們不停的按內存限制。它已經增加了好幾次,我想知道是否有一點增加它通常是一個壞主意?或者是只有這臺機器有多少RAM?

該機具有2GB的RAM和memory_limit的當前設置在1.5GB。我們可以輕鬆地爲機器添加更多內存(無論如何)。

有無其他人遇到這樣的問題?以及解決方案是什麼?

+6

老實說,你不應該關心設置內存限制,而是要弄清楚你的內存泄漏的位置並修復它。這不是一個增加memory_limit的解決方案,它避免了代碼中的問題。看看你正在設置哪些對象並取消設置值以清除泄漏。 – Petrogad 2009-09-15 04:42:53

+0

你能具體說明數據量嗎?你的意思是什麼? – jergason 2009-09-15 04:43:23

+8

@Frederico:OP並沒有試圖解決內存泄漏問題,他正在尋求處理PHP中非常大的數據集的解決方案。 – arul 2009-09-15 04:49:17

回答

53

用於運行PHP作爲Apache模塊服務器網頁的memory_limit的配置必須考慮到有多少Apache進程,你可以在同一時間在機器上 - 看到的Apache MaxClients配置選項。

如果MaxClients爲100並且您有2,000 MB或RAM,則非常快速的計算將顯示您不應該使用超過20 MB *(因爲20 MB * 100客戶端= 2 GB或RAM,即總數你的服務器有內存)*爲memory_limit值。

這是沒有考慮到有可能是在同一臺服務器上運行,例如MySQL,系統本身,......其他的東西,Apache是​​否可能已經在使用一些內存本身。

或課程,這也是一個「最壞的情況」,即認爲每個PHP頁面使用的最大內存量就可以了。


在你的情況,如果你需要的內存這麼大的量只有一個作業,我不會增加memory_limit爲PHP運行的Apache模塊。

相反,我會從啓動命令行(或通過cron作業)那份工作,而在這其中,只有指定的情況下更高的memory_limit specificaly。

這可以用PHP的-d選項來完成,如:

$ php -d memory_limit=1GB temp.php 
string(3) "1GB" 

考慮,在這種情況下,temp.php只包含:

var_dump(ini_get('memory_limit')); 

在我看來,這是比增加Apache模塊的PHP模塊的memory_limit更安全 - 這就是我通常在做大數據集時所做的事情,或者一些非常重的東西,我無法優化或分頁。


如果您需要爲PHP CLI執行時定義幾個值,你也可以告訴它使用而不是默認的PHP其他配置文件。INI,與-c選項:

php -c /etc/phpcli.ini temp.php 

這樣一來,您有:

  • /etc/php.ini爲Apache,低memory_limit,低max_execution_time ...
  • /etc/phpcli.ini的批次從命令運行 - 線,幾乎沒有限制

這確保您的批次將能夠運行 - 而且你會還有安全爲您的網站(memory_limitmax_execution_time是安全措施)


不過,如果你要優化你的腳本,你應該時刻;例如,在那種需要處理大量數據的情況下,分頁是必須的;-)

+0

是的,只有在需要它的過程中才會提高限制。不幸的是,在這種情況下分頁不會有幫助;最終的結果只有少數(20左右)的統計數字,只是需要空間的處理。 – 2009-09-15 05:11:16

+0

噢,好的......那麼,我想這取決於你啓動這個過程時有多少「免費」內存:如果你在半夜啓動它,當幾乎沒有人使用你的服務器時,也許1.5 GB可能是好的(我會用更多的,讓一些內存到系統的其他部分) - 但只有你可以說當時你的服務器加載了多少。 – 2009-09-15 05:23:15

+4

在某些PHP版本中(例如帶有Suhosin-Patch的PHP 5.3.15),設置爲1G,而不是1GB。測試它或PHP會將限制設置爲最低值,並且腳本將無法執行,例如,使用'php -d memory_limit = 1G -r'echo ini_get('memory_limit');「' – 2013-03-20 14:12:11

2

您是否嘗試將數據集分成較小的部分,並且只處理一部分?

如果您從磁盤文件中獲取數據,則可以使用fread()函數在數據庫中加載較小的塊或某些sort of unbuffered db query

我從v3.something沒有檢查過PHP,但是你也可以使用雲計算的一種形式。 1GB數據集看起來足夠大,可以在多臺機器上處理。

+0

該計劃僅根據需要讀取數據(正如您使用fread())所建議的那樣,但這是我們尚未得到的重構。 – 2009-09-15 05:27:39

+0

這是實際的正確答案,IMNSHO:除非數據集完全相關,否則通常可以一次處理一個部分,並且很少有必要將其全部保存在內存中。正如OP所指出的那樣,這通常需要不重構的重構。 – Piskvor 2015-12-15 10:06:40

1

鑑於您知道腳本中存在需要修復的內存問題,並且您只是在尋找短期解決方案,那麼我將不會解決go about profiling和解決內存問題的方法。這聽起來像你會去那。

所以,我說你要記住的主要事情是:在系統上

  • 總內存負載
  • 操作系統功能

PHP只是其中的小部分系統。如果你讓它吃掉大量的RAM,那麼其他進程就會受到影響,進而影響到腳本本身。值得注意的是,如果你從數據庫中提取大量數據,那麼你的DBMS可能需要大量內存才能爲你的查詢創建結果集。作爲一種快速解決方案,您可能需要確定正在運行的任何查詢並儘快釋放結果,以便爲長時間運行提供更多內存。

就操作系統功能而言,您應該記住,您可能正在運行的32位系統只能處理高達4GB的RAM,而無需特殊處理。取決於它的使用方式,限制通常要少得多。一些Windows芯片組和配置實際上可以有少於3GB的系統可用,即使是4GB或更多的物理安裝。你應該檢查你的系統能夠處理多少。

你說你多次增加了內存限制,所以顯然這個工作的範圍越來越大。如果你達到1.5Gb,那麼即使安裝2Gb更多的內存,聽起來也只是短暫的緩解。

有沒有人遇到過這種類型的 問題?以及解決方案是什麼?

我想你可能已經知道唯一真正的解決方案是分解並花時間儘快優化腳本,否則最終會導致工作量太大而無法運行。

+0

該機器非常專注於PHP,數據庫服務器是分開的。以前的限制增加並不是因爲工作在增加(雖然會增加,但不會那麼快),但他們不足以「解決」問題(所以我們嘗試了更大的限制)。我們現在有一個讓流程運行的限制,但它絕對只是一個短期解決方案。關於系統限制的好處是,它是一個64位機器,無論如何我們都會增加RAM。無論如何,我認爲你已經減輕了我​​的擔心,即在一個過程中拋出這麼多的記憶是荒謬的。 RDBMS是這樣做的,爲什麼我不能:) – 2009-09-15 06:29:47