简体   繁体   中英

dotMemory and tracking memory leaks

I have what I consider a basic web application MVC, EF6. The user has a dashboard that presents a table that contains data from two different database systems. MSSQL and Informix (Using IBM.Data.Informix).

Over time the IIS process just keeps eating away at the ram. I grabbed dotMemory to help me try to locate it but now trying to figure out how to read this data.

I left the web page open and every 10 seconds there is an Ajax call that returns the new data.

The 4th snapshot was taken a few hours after the 3rd one. 在此处输入图片说明

The total doesn't match the numbers below but something isn't as it should be.

The picture below seems to tell me I'm only using at most 10mb with my application.

在此处输入图片说明

I'm also still looking into the heap but it doesn't seem like this is where the big chunk is.

在此处输入图片说明 在此处输入图片说明 在此处输入图片说明

I'm still digging up videos and guides to help me figure out locating this issue. I'm using a lot of the built in framework and I really don't see an issue with the code I'm using unless there is a bug somewhere or I really am missing something I shouldn't be doing within the code.

DatabaseManager

public class DatabaseManager : IDisposable
{
    private bool disposed = false;
    private SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);

    private PatientCheckinEntities db { get; set; }

    private IfxConnection conn { get; set; }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    public DatabaseManager()
    {
        string ifxString = System.Configuration.ConfigurationManager.ConnectionStrings["ifx"].ConnectionString;
        conn = new IfxConnection(ifxString);
        db = new PatientCheckinEntities();
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            handle.Dispose();

            IfxClose();
            conn.Dispose();
            db.Dispose();
        }

        disposed = true;
    }

    private void IfxClose()
    {
        if (conn.State == System.Data.ConnectionState.Open)
        {
            conn.Close();
        }
    }

    private void IfxOpen()
    {
        if (conn.State == System.Data.ConnectionState.Closed)
        {
            conn.Open();
        }
    }

    public ProviderModel GetProviderByResourceID(string id)
    {
        ProviderModel provider = new ProviderModel();

        using (IfxDataAdapter ida = new IfxDataAdapter())
        {
            ida.SelectCommand = new IfxCommand("SELECT description FROM sch_resource WHERE resource_id = ? FOR READ ONLY", conn);
            IfxParameter ifp1 = new IfxParameter("resource_id", IfxType.Char, 4);
            ifp1.Value = id;
            ida.SelectCommand.Parameters.Add(ifp1);

            IfxOpen();
            object obj = ida.SelectCommand.ExecuteScalar();
            IfxClose();
            if (obj != null)
            {
                string name = obj.ToString();

                provider.ResourceID = id.ToString();
                string[] split = name.Split(',');

                if (split.Count() >= 2)
                {
                    provider.LastName = split[0].Trim();
                    provider.FirstName = split[1].Trim();
                }
                else
                {
                    provider.LastName = name.Trim();
                }

                ProviderPreference pp = db.ProviderPreferences.Where(x => x.ProviderID.Equals(id, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

                int globalWait = Convert.ToInt32(GetConfigurationValue(ConfigurationSetting.WaitThreshold));

                if (pp != null)
                {
                    provider.Preferences.DisplayName = pp.DisplayName;
                    provider.Preferences.WaitThreshold = pp.WaitThreshold.HasValue ? pp.WaitThreshold.Value : globalWait;
                }
                else
                {
                    provider.Preferences.WaitThreshold = globalWait;
                }
            }
        }

        return provider;
    }

    public List<PatientModel> GetCheckedInPatients(List<string> providers)
    {
        List<PatientModel> patients = new List<PatientModel>();

        foreach (string provider in providers)
        {
            List<PatientModel> pats = db.PatientAppointments
                        .Where(x => provider.Contains(x.ProviderResourceID)
                        && DbFunctions.TruncateTime(x.SelfCheckInDateTime) == DbFunctions.TruncateTime(DateTime.Now))
                            .Select(x => new PatientModel()
                            {
                                Appointment = new AppointmentModel()
                                {
                                    ID = x.AppointmentID,
                                    DateTime = x.AppointmentDateTime,
                                    ArrivalTime = x.ExternalArrivedDateTime
                                },
                                FirstName = x.FirstName,
                                LastName = x.LastName,
                                SelfCheckIn = x.SelfCheckInDateTime,
                                Provider = new ProviderModel()
                                {
                                    ResourceID = x.ProviderResourceID
                                }
                            }).ToList();

            patients.AddRange(pats.Select(x => { x.Provider = GetProviderByResourceID(x.Provider.ResourceID); return x; }));
        }

        using (IfxDataAdapter ida = new IfxDataAdapter())
        {
            ida.SelectCommand = new IfxCommand("SELECT arrival_time::char(5) as arrival_time FROM sch_app_slot WHERE appointment_key = ? FOR READ ONLY", conn);

            IfxOpen();
            foreach (PatientModel patient in patients)
            {
                ida.SelectCommand.Parameters.Clear();
                IfxParameter ifx1 = new IfxParameter("appointment_key", IfxType.Serial);
                ifx1.Value = patient.Appointment.ID;
                ida.SelectCommand.Parameters.Add(ifx1);

                using (IfxDataReader dr = ida.SelectCommand.ExecuteReader())
                {
                    while (dr.Read())
                    {
                        if (dr.HasRows)
                        {
                            string arrival = dr["arrival_time"].ToString();

                            if (!string.IsNullOrWhiteSpace(arrival) && !patient.Appointment.ArrivalTime.HasValue)
                            {
                                PatientAppointment pa = new PatientAppointment();
                                pa.AppointmentID = patient.Appointment.ID;
                                pa.AppointmentDateTime = patient.Appointment.DateTime;
                                pa.FirstName = patient.FirstName;
                                pa.LastName = patient.LastName;

                                string dt = string.Format("{0} {1}", patient.Appointment.DateTime.ToString("yyyy-MM-dd"), arrival);
                                pa.ExternalArrivedDateTime = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);
                                patient.Appointment.ArrivalTime = pa.ExternalArrivedDateTime;
                                pa.ProviderResourceID = patient.Provider.ResourceID;
                                pa.SelfCheckInDateTime = patient.SelfCheckIn;

                                db.PatientAppointments.Attach(pa);
                                db.Entry(pa).State = EntityState.Modified;
                                db.SaveChanges();
                            }
                        }
                    }
                }
            }
            IfxClose();
        }


        patients = patients.Select(x => { x.Appointment.WaitedMinutes = (int)Math.Round(((TimeSpan)x.Appointment.ArrivalTime.Value.Trim(TimeSpan.TicksPerMinute).Subtract(x.SelfCheckIn.Trim(TimeSpan.TicksPerMinute))).TotalMinutes); return x; }).ToList();

        List<PatientModel> sorted = patients.Where(x => !x.Appointment.ArrivalTime.HasValue).OrderBy(x => x.SelfCheckIn).ThenBy(x => x.Provider.ResourceID).ToList();
        sorted.AddRange(patients.Where(x => x.Appointment.ArrivalTime.HasValue).OrderBy(x => x.Appointment.DateTime).ThenBy(x => x.Provider.ResourceID));

        return sorted;
    }

    private string GetConfigurationValue(string id)
    {
        return db.Configurations.Where(x => x.ID.Equals(id)).Select(x => x.Value).FirstOrDefault();
    }
}

Controller

[HttpPost]
[Authorize]
public ActionResult GetCheckedIn(List<string> provider)
{
    DashboardViewModel vm = new DashboardViewModel();
    try
    {
        if (provider.Count > 0)
        {
            using (DatabaseManager db = new DatabaseManager())
            {
                vm.Patients = db.GetCheckedInPatients(provider);
            }
        }
    }
    catch (Exception ex)
    {
        //todo
    }
    return PartialView("~/Views/Dashboard/_InnerTable.cshtml", vm);
}

Your app consumes a lot of native memory, not .NET memory. Look at .NET memory consumption it's about 12Mb and does not grow intensively. It seems that you do not call Dispose method on some objects which uses native memory, eg database connection objects or something like that. Check a number of such objects if you does not release them the number will grow constantly.

I see you are using System.xml.Schema.... depending on the version, will create an unmanaged memory leak for each and every instance of about 80K. So, every 12 uses and you have a one meg memory leak in un-managed memory. Instead of creating a new one each time, cache it if possible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM