Hi,

Von: Markus Schaber 
>[Memory Leaks]

I now created a smaller stand-alone testcase simulating our environment, and 
isolated the following cases:

- using Python.SetTrace(engine, delegate) leaks about 165k per script 
invocation.

- importing the warning module from the hosting environment leaks about 1.4 M 
per script run.

- importing the os module from the script also leaks about 1.4M per script.

- Doing both imorts also leaks about 1.4M per script(!).

- Combining all three of the above leads to an OutOfMemory Exception after 
about 331 cycles, boiling down to a leak of ~5MB per script run!

- Doing none of the above (only print) apparently creates a leak-free program.

I attached the test program. For the test runs above, I compiled it for .NET 
4.0 and target "x86", as our production app also runs in that environment (.NET 
4.0 and 32-bit only).

I'll do further investigations (like memory dumping) tomorrow.

Best regards

Markus Schaber
-- 
___________________________
We software Automation.

3S-Smart Software Solutions GmbH
Markus Schaber | Developer
Memminger Str. 151 | 87439 Kempten | Germany | Tel. +49-831-54031-0 | Fax 
+49-831-54031-50

Email: m.scha...@3s-software.com | Web: http://www.3s-software.com 
CoDeSys internet forum: http://forum.3s-software.com
Download CoDeSys sample projects: 
http://www.3s-software.com/index.shtml?sample_projects

Managing Directors: Dipl.Inf. Dieter Hess, Dipl.Inf. Manfred Werner | Trade 
register: Kempten HRB 6186 | Tax ID No.: DE 167014915 


using System.Threading;

namespace IronPythonLeakTest
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using IronPython.Hosting;
    using IronPython.Runtime;
    using IronPython.Runtime.Exceptions;
    using IronPython.Runtime.Types;
    using Microsoft.Scripting;
    using Microsoft.Scripting.Hosting;
    using System.Windows.Forms;

    public static class ScriptExecutor
    {
        public static bool import_os = true;

        public static bool import_warnings = true;

        public static bool set_trace = true;

        private const string LIB_PATH = @"C:\Program Files (x86)\IronPython 
2.7.1\Lib";

        private static readonly Dictionary<string, object> 
DEFAULT_EXECUTION_OPTIONS =
            new Dictionary<string, object> { { "LightweightScopes", true } };

        private static int TraceCount;

        private static void Main()
        {
            long afterFirst = 0;
            long beforeStart = 0;
            try
            {
                beforeStart = GC.GetTotalMemory(true);

                Execute(0);

                afterFirst = GC.GetTotalMemory(true);

                for (int i = 1; i < 1000; i += 1)
                {
                    Execute(i);
                }
            }
            finally
            {
                for (int i = 0; i < 5; i += 1)
                {
                    Application.DoEvents();
                    GC.Collect();
                    Thread.Sleep(1000);
                    GC.WaitForPendingFinalizers();
                }

                long afterLast = GC.GetTotalMemory(true);

                Console.WriteLine("Script Finished");
                Console.WriteLine("First run: {0}Mb, 1000 runs: {1}Mb", 
(afterFirst - beforeStart) / (1024 * 1024), (afterLast - beforeStart) / (1024 * 
1024));
                Console.ReadLine();
            }
        }

        private static void Execute(int i)
        {
            DateTime start = DateTime.Now;

            string src = "from __future__ import print_function \n";
            
            if (import_os) src += "import os \n";

            src += string.Format("print('hallo: ', {0}) \n", i);
            
            ScriptEngine engine = 
Python.CreateEngine(DEFAULT_EXECUTION_OPTIONS);
            
            ScriptRuntime runtime = engine.Runtime;
            ScriptScope mainScope = engine.CreateScope();

            runtime.LoadAssembly(typeof(IronPython.Modules.PythonNT).Assembly);


            ScriptSource scriptSource = 
engine.CreateScriptSourceFromString(src, "TestScript", 
SourceCodeKind.AutoDetect);

            scriptSource.Compile(new 
global::IronPythonLeakTest.ErrorListenerImpl());
            ScriptSource source = scriptSource;

            // Set the search pathes.
            engine.SetSearchPaths(new[] { LIB_PATH });

            if (set_trace)
            {
                engine.SetTrace(TraceBackHandler);
            }

            if (import_warnings)
            {
                var warningModule = engine.ImportModule("warnings");
                warningModule.SetVariable("showwarning", new 
ShowWarning(ShowWarning));
            }

            source.Execute(mainScope);

            Console.WriteLine("{0}: {1} - {2}", i, ScriptExecutor.TraceCount, 
(DateTime.Now - start).Milliseconds);
        }


        private static void ShowWarning(CodeContext context, object message, 
PythonType category, string filename, int lineno, object file, string line)
        {
            Console.WriteLine(message ?? "");
        }

        private static TracebackDelegate TraceBackHandler(TraceBackFrame 
stackFrame, string stEvent, object payload)
        {

            TraceCount += 1;

            return TraceBackHandler;
        }
    }

    public delegate void ShowWarning(
        CodeContext context, object message, PythonType category, string 
filename, int lineno,
        [DefaultParameterValue(null)] object file, 
[DefaultParameterValue(null)] string line);

    class ErrorListenerImpl : ErrorListener
    {
        public override void ErrorReported(ScriptSource source, string 
stMessage, Microsoft.Scripting.SourceSpan span, int errorCode, 
Microsoft.Scripting.Severity severity)
        {
            Console.WriteLine(stMessage);
        }
    }
}


_______________________________________________
Ironpython-users mailing list
Ironpython-users@python.org
http://mail.python.org/mailman/listinfo/ironpython-users

Reply via email to