###前提・実現したいこと
Ruby on Sinatraで極秘のシステムを作っています。
MySQLからselect文で読む時に以下↓のエラーメッセージが発生しました。
発生した箇所まで突き止めましたが必ず発生するわけではないようなので、設定メモリが小さ過ぎてメモリリークが実際に起きているのかもしれないと疑っております。
メモリリークの防ぎ方、またはSinatraでの使用可能メモリの増やし方、NoMemoryErrorと出ているがバグでじつは全く別の原因?かなど、ご教授願います。
###発生している問題・エラーメッセージ
NoMemoryError failed to allocate memory /magi/source/class/magiAdmin.rb:258:in `each' /magi/source/class/magiAdmin.rb:258:in `fuckinMethod' /magi/source/class/magiAdmin.rb:206:in `fuckin' /magi/source/online/web/pgeIndex.rb:84:in `httpGetfuck'
###該当のソースコード
ruby
1 2def fuckinMethod(strJobNameEN) 3 4 # create select sql 5 sqlSelect = 6 %Q{ select SQLLine \n} + 7 %Q{ from admin_log_sql \n} + 8 %Q{ where JobNameEN = '#{strJobNameEN}' \n} + 9 %Q{ order by LineNo asc \n}; 10 11 # run select sql 12 strSQL = ""; 13 rstDataset = self.runSQLSelect(sqlSelect); 14 # ↓ここでNoMemoryError発生(する時としない時がある) 15 rstDataset.each() do |recDataset| 16 # ↑ 17 strSQL = %Q{#{strSQL}#{recDataset["SQLLine"]}\n}; 18 end 19 20end 21 22def runSQLSelect(strSQL) 23 24 self.statusSQL(); 25 26 # connect to mysql server 27 objClient = nil; 28 objClient = Mysql2::Client.new( 29 :host => "localhost", 30 :username => @recUserInfo.strDBUser, 31 :password => @recUserInfo.strDBPass, 32 :database => "magi"); 33 34 # start transaction 35 begin 36 rstDataset = objClient.query(strSQL); 37 rescue => e 38 objClient.query("rollback"); 39 objError = SQLException.new(e.message, e.backtrace, strSQL); 40 ensure 41 objClient.close(); 42 objClient = nil; 43 end 44 45 if objError != nil then 46 raise objError; 47 end 48 49 self.debugSQL(strSQL, rstDataset); 50 self.statusProcess(); 51 52 return rstDataset; 53 54end 55 56# ###*********************************************************************### 57# # debug sql 58# ###*********************************************************************### 59 60def debugSQL(strSQL, rstDataset) 61 62 if @flgDebug then 63 64 @hshResult.delete(:sql); 65 @hshResult[:sql] = strSQL; 66 @hshResult.delete(:dataset); 67 @hshResult[:dataset] = self.debugSQL_display(rstDataset); 68 69 end 70 71end 72 73# ###=====================================================================### 74# # debug sql - display dataset 75# ###=====================================================================### 76 77def debugSQL_display(rstDataset) 78 79 lstDataset = Array.new(); 80 if rstDataset != nil then 81# ここから↓ 82 rstDataset.each() do |recDataset| 83 recDataset.each() do |strKey, datValue| 84 hshRow = Hash.new(); 85 hshRow[:key] = strKey; 86 hshRow[:value] = datValue.to_s(); 87 lstDataset.push(hshRow); 88 end 89 break; 90 end 91# ↑ここまでの処理を行わない時はエラーが起きない 92 end 93 94 return lstDataset; 95 96end
###メモリの空き
console
1 total used free shared buffers cached 2Mem: 16269900 3770256 12499644 0 294024 2722060 3-/+ buffers/cache: 754172 15515728 4Swap: 16609276 53336 16555940 5
###気になっていること
他のページではMySQLからselect文2回発行までは問題なく動いております。
今回のページは4回発行の4回目で失敗しております。
(必ず失敗するわけでもない)
4回目のSQL発行を無くし3回のみにするとNoMemoryErrorは発生しなくなります。
Sinatraのウェブページ表示は@付きの変数に処理結果を入れて*.erbファイルから参照してウェブページに表示するというものです。自分の場合は変数を増やしたくないので@hshResultというハッシュに色々と追加して、ウェブページで表示をしております。
どこかのサイトでrubyのHashに値を突っ込んでいくとメモリをどんどん消費して、何故かガベレージコレクタにも検知されず解放されない?というのを前に見た覚えがあります。自分は@hshResult = nil;することでメモリ解放をしているつもりなのですが、これはやり方としてあってますでしょうか?
###試したこと
debugSQL_display()でrstDataset.each()でselect結果を一度読み込んでいます。
この読み込みを辞めるとエラーが発生しなくなりました。
(読み込み結果をhashでarrayに入れてますがこの処理があってもなくてもエラーになります)
つまり結果データセットのeach()を2回目に発行した場合にMySQLのgem内でメモリエラーが起きたり起きなかったりしているみたいです。
MySQLからの結果データセットをeach()で読み込んだ後、読み込み開始位置?が最後のレコードになっている状態で、再度each()を発行するとダメということでしょうか?そもそも根本的に結果データセットのeach()について自分が勘違いしているかも知れませんので、(動くようにはなりましたが)自己解決にはしないことにします。
どなたか詳しい方、ご教授お願い致します。
###補足情報(言語/FW/ツール等のバージョンなど)
ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-linux-gnu]
sinatra 1.4.5
MySQL 5.5.32-0ubuntu7 (Ubuntu)
回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/04/24 23:14
2016/04/24 23:25
2016/04/25 22:00
2016/04/26 19:53