Skip to content

Memory leak named parameter holds entity references #3030

Closed
@philiphoy

Description

@philiphoy

Investigating a memory leak in an app, it was evident that the NHibernate.Engine.Query.QueryPlanCache was holding on to references to entities via instances of NHibernate.Param.NamedParameter. This only happens if the linq query expression embeds the entity itself as a parameter.

Below is a complete example which demonstrates this behaviour, note that only the first time a unique query is used is the entity pinned, see var first_reference_is_not_null = firstReference.Target; :

using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Mapping;
using NHibernate;
using NHibernate.Dialect;
using NHibernate.Tool.hbm2ddl;

public class programm
{
    public static void Main()
    {
        WeakReference sessionReference = null;
        WeakReference firstReference = null;
        WeakReference secondReference = null;

        new Action(() =>
        {
            var session = ConfigureSessionFactory();

            var first = new Test() { Id = 1 };
            var second = new Test() { Id = 2 };

            var f = session.Query<Test>().FirstOrDefault(f => f == first);
            var s = session.Query<Test>().FirstOrDefault(f => f == second);


            sessionReference = new WeakReference(session, true);
            firstReference = new WeakReference(first, true);
            secondReference = new WeakReference(second, true);

            session.Dispose();
        })();

        GC.Collect();
        GC.WaitForPendingFinalizers();

        var session_reference_is_null = sessionReference.Target;
        var first_reference_is_not_null = firstReference.Target;
        var second_reference_is_null = secondReference.Target;
    }

    private static ISession ConfigureSessionFactory()
    {
        var configuration = Fluently.Configure().Database(SQLiteConfiguration.Standard.InMemory).Mappings(m =>
        {
            m.FluentMappings.AddFromAssemblyOf<Test>();
        });

        configuration.ExposeConfiguration(c => SchemaMetadataUpdater.QuoteTableAndColumns(c, new MsSql2012Dialect()));

        var config = configuration.BuildConfiguration();

        var factory = config.BuildSessionFactory();
        var session = factory.OpenSession();
        var wr = new StringWriter();

        new SchemaExport(config).Execute(true, true, false, session.Connection, wr);
        var t = wr.ToString();
        return session;
    }

    public class TestMap : ClassMap<Test>
    {
        public TestMap()
        {
            Id(x => x.Id).GeneratedBy.Assigned();
        }
    }

    public class Test
    {
        public virtual int Id { get; set; }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions