Fatal error: Allowed memory size of 524288000 bytes exhausted (tried to allocate 64 bytes) in D


 

 

Fatal error: Allowed memory size of 524288000 bytes exhausted (tried to allocate 64 bytes) in D

從數據庫里面下載一百萬條數據 導入CSV文件里面出現這種錯誤

進行如下修改  打開 my.ini 修改  將max_allowed_packet改大

 

但是這些並不能解決根原問題,在寫函數的時候  要及時的銷毀 不用的變量, 對變量盡量用引用

如:                        

  

除此之外還要分配

原來是php.ini中的內存分配的問題,默認php代碼能夠申請到的最大內存字節數就是134217728 bytes,如果代碼執行的時候再需要更多的內存,就會報錯了,於是就將php.ini文件中的配置改了一下

        

form:http://www.jb51.net/article/57237.htm

 

 

                       這是更詳細的

 

背景

這個問題由一個同事問到的一次導入數據引發。一個很常見的操作,將數據從一個表中dump出來,在用mysql < a.sql的方式導入到另一個庫的一個表中。

在執行導入的時候,提示 MySQL server has gone away。在追查的時候突然想到會不會是因為max_allowed_packet太小導致的。將max_allowed_packet改大,確實解決了問題。

(史平忠的方法是修改my.ini 的 max_allowed_packet 為 20M,然后重啟mysql服務器,問題解決)

本文基於在此之后想到的兩個問題:

1、              MySQL server has gone away這個提示很不友好,是不是所有的包超過大小都是報這個?

2、              對於出現這種不友好的錯誤提示,有什么方法定位原因(而不是靠“突然想到”)?

追查1

步驟:a) 把max_allowed_packet設置為一個比較小的值, set global max_allowed_packet=16384

b) 寫一個簡單的語句 insert into tb values(xxx),(xxx),(xxx)……(xxx) 讓這個文件足夠大,比如我測試使用 a.sql大小為37318

c) 執行導入語句,提示 ER2ROR 1153 (08S01) at line 1: Got a packet bigger than ‘max_allowed_packet’ bytes

初步結論是並不是所有的語句太大都會導致直接顯示gone away。如果都是后面這個提示就好了,一目了然,用戶自然會去修改max_allowed_packet。

因此我們的問題就變成:為什么會有不同的提示?

分析1

  我們將報gone away的稱為場景1,另外一個稱為場景2.

場景1執行的sql語句大小是16554913

實際上場景2的返回信息是由MySQL服務端返回的,因為服務端才能判斷得到包大小超過。那么場景1為什么不是相同的提示呢?是不是壓根兒請求就沒有發到服務端?

照這個思路查到下面代碼(clent/mysql.cc)

其中場景1執行到2785行return了,而場景2是在調用2786行的put_error中輸出上述信息的。

這證實了上面的結論,場景1是在調用請求的時候提示的失敗,還沒有到服務端判斷包大小的環節。但是問題又來了,發送失敗為什么要提示gone away?我們最常見到的gone away,是執行期間MySQL重啟了,但這個case里面mysql並沒有重啟(這個很容易確認)。

分析1-2

進到mysql_real_query里面看看。發現執行路徑差別在此(sql-common/client.c)

場 景1調用net_write_command失敗,會執行到行854,場景2調用成功。就是說場景2里面,整個語句是都發給服務端成功的,因此服務端可以 做后續的判斷(包大小)。而場景1由於發命令失敗,執行到mysql_reconnect.。但進入mysql_reconnect發現沒有必要重發(我 們是普通的客戶端),然后發現一處hard code。

這里就是罪魁禍首了。因為mysql->reconnect為空,說明這里不需要重新連接。於是就直接在set_mysql_error中傳入 CR_SERVER_GONE_ERROR, 輸出在客戶端就是gone away。

至於為什么場景1發送會失敗,關鍵就是內容太大,tcp都不讓它發了(write調用失敗)

追查2

其實筆者覺得這個問題反而比較有意義,gone away這種錯誤提示不友好,會導致追查很難下手。有一個固定的步驟來查,避免抓瞎。

從上面的分析知道,由於之前的調用失敗,客戶端試圖進行“重連”,但是由於mysql->reconnect為0導致返回gone away。可以從這里下手。獲取在執行mysql_reconnect之前的那個錯誤號。

一個debug命令文件

[dingqi.lxb@rds064076 master]$ cat x.debug

set args   -Srun/mysql.sock -uroot   test < b.sql
b mysql_reconnect
r
c
f 1
p mysql->net.last_errno

在shell執行 gdb mysql  -x x.debug
$1 = 1160

這個1160就是我們要的了,

./include/mysqld_ername.h:{ “ER_NET_ERROR_ON_WRITE”, 1160, “Got an error writing communication packets” },

表明了真正的錯誤是交互時發包失敗。

小結

都是包太大,只是一個大過頭了,導致在失敗在客戶端發生,又由於重連時的hard code,導致了一個不友好的提示 gone away。

神馬?你也碰到這種情況但不是max_allowed_packet 的問題,但是你的mysql沒有debug信息?載一個源碼安裝。或者可以將你的復現步驟發給我。#異常gone away收集中#

 

原創文章,轉載請注明: 文章地址MySQL數據庫關於一次導入數據提示的MySQL server has gone away

訂閱本站: http://feed.mysqlops.com   轉載請注明來源,如果喜歡本站可以Feed 訂閱本站。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM