Home | News | Documentation | Download

Minuit 2 Memory Leak

Appologies if this has already been reported, I believe I have observed a memory leak when using Minuit2.

I haven’t yet fully figured out where this leak comes from. However the code which I will provide below consumes about 32 GB after 400 iterations.

On another issue, this is a 1 parameter fit, and it is incredibly slow to run. Is there a lot of overhead with the Minuit2 library? I tried moving some of the Minuit2 objects out of the inner loop to reduce the amount of memory allocation/deallocation. It didn’t seem to improve performance. So perhaps my code is slow due to the operator() calculation.

Still, this is currently running, iteration 55, and using 4 GB of ram. I can presumably fix the issue by putting the Minuit2 objects back inside the inner loop, as they seem to free memory correctly on destruction. However I thought someone might want to know this can be an issue and investigate.

Cheers!

    h_mps = new TH2D(mps_name, mps_name,
                           301, -0.1, 1.9,
                           301, 0.95, 1.45);

    h_mps_efficiency = new TH2D(mps_efficiency_name, mps_efficiency_name,
                           301, -0.1, 1.9,
                           301, 0.95, 1.45);

    std::vector<double> params;
    params.push_back(0.0); // A
    params.push_back(0.0); // B
    params.push_back(1.0); // C
    std::vector<double> param_errs;
    param_errs.push_back(0.0); // A
    param_errs.push_back(0.0); // B
    param_errs.push_back(0.1); // C

    // initialization
    ROOT::Minuit2::MnUserParameterState theParameterStatePersistent;
    ROOT::Minuit2::VariableMetricMinimizer theMinimizer;
    MinimizeFCN_FAST theFCN;
    
    ROOT::Minuit2::MnStrategy theStrategy(1); // no clue what it does

    theFCN.h_pointerto_data_p1 = h_data_p1;
    theFCN.h_pointerto_data_p2 = h_data_p2;

    theParameterStatePersistent.Add("C", params.at(2), param_errs.at(2));

    std::chrono::system_clock::time_point master_start_time = std::chrono::high_resolution_clock::now();

    for(Int_t i = 1; i <= h_mps->GetNbinsX(); ++ i)
    {
        std::cout << "i=" << i << "/" << h_mps->GetNbinsX() << std::endl;

        for(Int_t j = 1; j <= h_mps->GetNbinsY(); ++ j)
        {
            
            double A0 = 0.0;
            double A2 = 0.0;

            {
                const double xi_31 = h_mps->GetXaxis()->GetBinCenter(i);
                const double A = h_mps->GetYaxis()->GetBinCenter(j);

                convert_ps_coeff_forward(A, xi_31, A0, A2);
            }


            ///////////////////////////////////////////////////////////////////
            // calculate chi2
            ///////////////////////////////////////////////////////////////////

            params.at(0) = A0;
            params.at(1) = A2;
            params.at(2) = 1.0;
            param_errs.at(0) = 0.0;
            param_errs.at(1) = 0.0;
            param_errs.at(2) = 0.1;

            double chi2_p1, chi2_p2;

            ///////////////////////////////////////////////////////////////////
            // perform fit
            ///////////////////////////////////////////////////////////////////

            SYS_COVMATRIX_ENABLE_MINUIT = true;
            SYS_COVMATRIX_ENABLE_CALC = true;

            // initialize
            theFCN.A_G0 = params.at(0);
            theFCN.A_G2 = params.at(1);

            theParameterStatePersistent.SetValue(0, params.at(2));
            theParameterStatePersistent.SetError(0, param_errs.at(2));

            // exec
            ROOT::Minuit2::FunctionMinimum FCN_min =
                theMinimizer.Minimize(theFCN, theParameterStatePersistent, theStrategy);

            double eff = FCN_min.UserParameters().Params().at(0);
            double chi2 = FCN_min.Fval();

            h_mps->SetBinContent(i, j, chi2);
            h_mps_efficiency->SetBinContent(i, j, eff);

        } // h_mps j


        std::chrono::system_clock::time_point outloop_end_time = std::chrono::high_resolution_clock::now();

        std::chrono::duration<double> total_runtime_sec = outloop_end_time - master_start_time;
        int number_of_runs_completed = i + 1;
        int number_of_runs_remaining = 301 - (i + 1);
        double remaining_runtime_sec = total_runtime_sec.count() / (double)number_of_runs_completed * (double)(number_of_runs_remaining);
        double remaining_runtime_hr = remaining_runtime_sec / 3600.0;
        std::cout << "ETA: " << remaining_runtime_hr << " h" << std::endl;


    } // h_mps i

ROOT Version:

ROOT Version: 6.18/04
Built for linuxx8664gcc on Sep 11 2019, 15:38:23
From tags/v6-18-04@v6-18-04

Platform: Linux x86_64
Compiler: gcc


My applogies, I think I have tracked the issue down to my own code, where I allocate TMatrix objects.

I am guessing these are not managed internally by ROOT memory manager. If so, this is the source of the memory leak. Nothing to do with Minuit2.

1 Like

Just to confirm - it seems that ROOT does not manage the memory of TMatrix objects automatically. This was the cause of the issue. (In case anyone was wondering.)