1. 程式人生 > >c# tensorflow 記憶體洩露問題

c# tensorflow 記憶體洩露問題

記憶體洩露,造成原因有new完以後不釋放,程式碼放在迴圈中 ,new 大物件,記憶體很快耗光,舉個例子,乾淨的紙上用鉛筆亂畫東西,整個紙面畫完以後,就沒地方畫了,要想再畫的話,得用橡皮擦了。借別人的東西,老是不歸還,再借用的話,就不借給了。房間裡堆滿了東西,再往進放的話,就放不進去了。等等,生活中好多這樣的例子。看一下下面程式碼

using (MemoryStream ms = new MemoryStream())
            {
                try
                {
                    bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                }
                catch
                {
                    return false;
                }
                var runner = session.GetRunner();
                var tensor = CreateTensorFromImage(ms.GetBuffer());

                runner.AddInput(graph["input"][0], tensor).Fetch(graph["output"][0]);

                var output = runner.Run();
                var result = output[0];
                var rshape = result.Shape;

                if (result.NumDims != 2 || rshape[0] != 1)
                {
                    var shape = "";
                    foreach (var d in rshape)
                    {
                        // shape += $"{d} ";
                    }
                    shape = shape.Trim();
                    Environment.Exit(1);
                    return false;
                }

                bool jagged = true;

                var bestIdx = 0;
                float best = 0;

                if (jagged)
                {
                    var probabilities = ((float[][])result.GetValue(jagged: true))[0];
                    for (int i = 0; i < probabilities.Length; i++)
                    {
                        if (probabilities[i] > best)
                        {
                            bestIdx = i;
                            best = probabilities[i];
                        }
                    }

                }
                else
                {
                    var val = (float[,])result.GetValue(jagged: false);
                    for (int i = 0; i < val.GetLength(1); i++)
                    {
                        if (val[0, i] > best)
                        {
                            bestIdx = i;
                            best = val[0, i];
                        }
                    }

                }

                this.Invoke(new Action(() =>
                {
                    //nizh modify
                    string tmpStr = labels[bestIdx];
                    if (tmpStr.IndexOf("sandship") != -1)
                    {
                        label1.Text = "XXXX_" + tmpStr;
                    }
                    else { label1.Text = tmpStr; }
                    label1.Refresh();
                }
                )
               );

                if (tensor != null)
                {
                    tensor.Dispose();
                    tensor = null;
                }
                if (result != null)
                {
                    result.Dispose();
                    result = null;
                }
                if (ms != null)
                {
                    ms.Close();
                    ms.Dispose();
                }
                if (bmp != null)
                {
                    bmp.Dispose();
                    //bmp = null;
                }
            }
            GC.Collect();
            GC.SuppressFinalize(this);

檢視帶有Dispose()的程式碼行,起初是沒有這些的,一起動程式,4個g記憶體很快就沒了。
GC.Collect();垃圾回收

var tensor = TFTensor.CreateString(contents);

            TFGraph graph;
            TFOutput input, output;

            // Construct a graph to normalize the image
            ConstructGraphToNormalizeImage(out graph, out input, out output);

            // Execute that graph to normalize this one image
            using (var session = new TFSession(graph))
            {
                var normalized = session.Run(
                         inputs: new[] { input },
                         inputValues: new[] { tensor },
                         outputs: new[] { output });
                if (session!=null)
                {
                    session.Dispose();
                }
                if (tensor!=null)
                {
                    tensor.Dispose();
                }
                if (graph!=null)
                {
                    graph.Dispose();
                }
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
                return normalized[0];
            }

檢視Dispose程式碼行,銷燬就不洩露了。不銷燬就洩露。
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
有必要時用上邊3行程式碼回收記憶體。

            const int W = 224;
            const int H = 224;
            const float Mean = 117;
            const float Scale = 1;
            graph = new TFGraph();
            input = graph.Placeholder(TFDataType.String);
            output = graph.Div(
                x: graph.Sub(
                    x: graph.ResizeBilinear(
                        images: graph.ExpandDims(
                            input: graph.Cast(
                                graph.DecodeJpeg(contents: input, channels: 3), DstT: TFDataType.Float),
                            dim: graph.Const(0, "make_batch")),
                        size: graph.Const(new int[] { W, H }, "size")),
                    y: graph.Const(Mean, "mean")),
                y: graph.Const(Scale, "scale"));
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();