Luaにおけるメモリ管理と解放の理解

6373 ワード

Luaメモリは自動的に収集され、Javaと同様に、オブジェクトやグローバル変数に参照されないデータは、まず回収としてマークされ、開発者が何もする必要はありません.しかし、Javaにもメモリが漏れるようにLuaもありますが、C++とは異なり、コード実行によってロードされたリソースが完全に破棄されていないため、その中で最も悪名高いのは、局所変数をグローバル変数(local修飾子を忘れた)に宣言してしまったことです.このようなメモリ漏洩は、他の言語のメモリ漏洩と同様に発生しやすいが、気づきにくく、開発されたアプリケーションに潜在的な大きな危険をもたらす.
では、この隠れた危険を解決するための有効な解決策はありますか?答えはcollectgarbageです.collectgarbageとは、Luaの開発者に開放する、Luaのメモリ使用状況(collectgarbage(「count」)を傍受するためのものであり、同時にcollectgarbage(「collect」)を提供し、適切な時に明示的な回収を行うことができる.
では、コードをテストしてcollectgarbageをどのように遊ぶかを見てみましょう.
まず、明らかな対比のために、まず漏洩が発生していない場合を見て、以下のtest 1(コードは以下の通り)を実行します.
function test1( ... )
  collectgarbage("collect");--        ,              
  local  c1 = collectgarbage("count")
  print("   ,Lua    ",c1)
  local colen = {}--   ,colen     
  print("  ,  5000   ,   colen ")
  for i=1,50000 do
    table.insert(colen,{}) --          ,          
  end
  local c2 = collectgarbage("count")
  print("     :",c2)
end
test1()

実行結果は以下の通りです.最初はLuaのメモリが23.765625で、5000個の配列を宣言し、colenに追加した現在のメモリは3782.2734375[Finished in 0.1 s]です.
ここで、localによって宣言されたcolenは5000配列追加され、test 1呼び出し後、メモリは約300 K(25906 K-25620 K)増加した.次に、メモリ回収を行います(mem関数を呼び出します.コードは次のとおりです).
function mem( )
    print("  GC  ..")
    local c2 = collectgarbage("count")
    collectgarbage("collect")
    print("   ,   Lua   ",c2)
end

実行結果は以下の通りである:@@@@@@呼び出しtest 1が最初、Luaのメモリは24.5205078125現在、5000個の配列を宣言し、colenに追加する現在のメモリは:3783.0283203125@@@@@呼び出しtest 1完了呼び出しGC収集..収集後、現在のLuaメモリは3783.201171875でGC収集を呼び出す..収集後、現在のLuaメモリは24.77005078125でGC収集を呼び出す.収集後、現在のLuaメモリは24.76953125でGC収集を呼び出す.収集後、現在のLuaメモリは24.76778125[Finished in 0.1 s]
(メモリの安定を確保するために、以上注意memが複数回呼び出され、さらに2回目になるとメモリが下がり始め、最後には24.778125 Kで安定しているのが見えます)よし、最初の3783.201171875 Kから、回収後の24.7677578125 Kまで、複数回呼び出された後、両者に変化はありません.つまり、関数test 1の実行は、回収できないメモリは発生していません.漏れは現れなかった.
はい、現在、漏洩したtest 2が実行されています(コードは以下の通りです).test 2はtest 1と比較して、colenがグローバルに誤って宣言された点だけ違います.
function test2( ... )
  collectgarbage("collect");--        ,              
  local  c1 = collectgarbage("count")
  print("   ,Lua    ",c1)
  colen = {}--   ,colen     
  print("  ,  5000   ,   colen ")
  for i=1,50000 do
    table.insert(colen,{}) --          ,          
  end
  local c2 = collectgarbage("count")
  print("     :",c2)
end
print("@@@@@test2")
test2()
print("@@@@@test2  ")

実行結果は以下の通りである@@@@@test 2が最初、Luaのメモリは24.451015625現在、5000個の配列を宣言し、colenに加算された現在のメモリは:3782.9619140625@@@@test 2が完了した[Finished in 0.1 s]つまり、メモリも3782.9619140625であり、test 1とほぼ同等である.よし、今から回収(mem)関数を呼び出し、結果は以下の通りである.
GC収集を呼び出す..収集後、現在のLuaメモリは3783.197265625でGC収集を呼び出す.収集後、現在のLuaメモリは3783.1962890625でGC収集を呼び出す.収集後、現在のLuaメモリは3783.197265625でGC収集を呼び出す.収集後、現在のLuaメモリは3783.1962890625
関数回収が実行することを保証するために、今回、合計4回mem関数(以上の印刷行数を参照)が呼び出されたが、上記の結果から見ると、残念ながら1回目から最後の4回目までメモリは3783に安定している.左右、つまりtest 2を呼び出す前に比べて、Luaがメモリ回収を行ってもメモリは落ちないように見えますが、この数千Kメモリは、グローバル関数に格納されているため、いつまでも回収される機会がありません!
まとめ1:Luaのプログラミングによるメモリ漏洩をどのように監視するか:
  • 漏洩が発生する関数に対してcollectgarbage(「count」)を呼び出し、最初のメモリ使用
  • を取得する.
  • 関数呼び出し後、collectgarbage(「collect」)を収集し、collectgarbage(「count」)を使用して現在のメモリを取得し、最後に2回の使用差
  • を記録する.
  • test 1の収集から、collectgarbage(「collect」)が呼び出され、一度の成功は保証されないため、
  • を複数回呼び出すことができる.
    まとめ2:Luaアプリケーションで発生するメモリの過大な使用を回避する方法:
  • はもちろん、グローバル変数が存在するため、マルチスレッドが安全ではない可能性があるため、コード実装に漏洩は発生せず、グローバル変数の使用を避ける.複数のlua仮想マシンを作成すると、2つのスレッドが同時に1つの変数を操作します.この時点で問題が発生します
  • テストでは、Luaに割り当てられたメモリは、実際には自動的に回収されない(個人的にはLua仮想マシンがこのことをしていないか、回収のタイミングがC層にあると推定される)ため、メモリが大きすぎるのを避けるために、アプリケーションの実行時には定期的に(collectgarbage(「collect」)を呼び出す必要がある可能性があります.またはcollectgarbage(「step」)を明示的に回収する.

  • 参考リンク:http://blog.csdn.net/henren555/article/details/17579153