DLL内存中的DLL内存泄漏

时间:2014-09-09 15:02:22

标签: c# c++ opencv dll

我正在调试某人的代码而我收到错误:这可能是由于堆的损坏,这表明.exe或其加载的任何DLL中存在错误。我研究并了解到这是由于一些内存泄漏,对象没有从堆中正确删除。我查看并查看了代码(逐行调试),并在return语句中崩溃。这是代码:问题出在哪里?

首先调用DLL的c#代码

    public class Analysis
    {
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1), Serializable]
        public struct Pothole
        {
            public int Id;
            public int FrameNumber;
            public int LeftX;
            public int TopY;
            public int Width;
            public int Height;
            public int Certainty; // note that this is a percentage value, hence integer
            public double Latitude;
            public double Longitude;
            public double Speed;
            public double Area;
            public double Volume;
            [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string TimeCreated;
            [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 200)]
            public string CroppedImage;
            [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 200)]
            public string LeftImage;
            [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 200)]
            public string RightImage;
        };

        private int progress;
        public int Progress
        {
            get { return progress; }
            set { progress = value; }
        }

        public List<FileInfo> AllVideoFiles;
        public List<FileInfo> FramesInDir;
        public List<GpsPoint> GpsList;
        public VideoMetaData MetaData;
        public List<TrackPothole> PotholeList;
        public VideoHandling VideoHandler;

        public int verbose; //if verbose, then you get a lot of wordy output on what the program is doing

        private VspDatabaseEntities1 _vde;        

        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate void ProgressCallback(int value);
        public event ProgressCallback OnProgressUpdated;

        //initializes video files and calibraiton file names
        [DllImport(@"Analyser.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public static extern int Initialize(string SettingsDir, int SettingDirLength, string LeftVideoFile, int LeftFileLength, 
            string RightVideoFile, int RightFileLength, string GpsCoordsFile, int GpsFileLength, string OutputDirectory, int OutputDirLength);

        //analyse road files (do everything)
        [DllImport(@"Analyser.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        public static extern int Start([MarshalAs(UnmanagedType.FunctionPtr)] ProgressCallback callbackPointer, int verbose);

        //Does the analysis of videos, uses the c++ analysis Start() function
        public void Go(ProgressBar bar)
        {
            //flag -> should actually be set outside of function, can't find the outside
            verbose = 1;            

            //obtain parameters from settings.settings
            string inputDir = Properties.Settings.Default["InputDir"].ToString();
            string outputDir = Properties.Settings.Default["OutputDir"].ToString();
            string settingsDir = Properties.Settings.Default["SettingsDir"].ToString();

            //setup directories and filenames            
            //string camfile = settingsDir + "\\" + "Calib.yaml"; => now we send the directory, not the specific file
            string rightvid = "";
            string leftvid = "";
            string gpsfile = "";

            //Associate multiple files according to creation times and loop through matching pairs 
            //(this works because of the copy operation? -> but won't everything have the same time then?)
            AllVideoFiles = GetFiles(inputDir, "*.avi");            
            List<FileInfo> rightvids = new List<FileInfo>(AllVideoFiles.Where(v => v.FullName.Contains("3D_R")).OrderBy(v => v.CreationTime));
            List<FileInfo> leftvids = new List<FileInfo>(AllVideoFiles.Where(v => v.FullName.Contains("3D_L")).OrderBy(v => v.CreationTime));
            List<FileInfo> gpsfiles = new List<FileInfo>(GetFiles(inputDir, "*.txt").OrderBy(g => g.CreationTime));
            Console.WriteLine("Got this far1");
            //Check that the number of right and left video files and gps files match
            int lowestCount = 0;
            if (rightvids.Count != leftvids.Count)
            {
                MessageBox.Show("Error: The number of right camera videos does not match the number of left camera videos!");
                if (rightvids.Count < leftvids.Count)
                    lowestCount = rightvids.Count;
                else
                    lowestCount = leftvids.Count;
            }
            else
                lowestCount = rightvids.Count;

            if (gpsfiles.Count != lowestCount)
            {
                MessageBox.Show("Error: The number of gps data files does not match the number of right camera video files!");
                if (gpsfiles.Count < lowestCount)
                    lowestCount = gpsfiles.Count;
            }

            //@todo 
            //Currently, looping through the files and hoping there is only one in the file.
            Console.WriteLine("Got this far2");
            for (int i = 0; i < lowestCount; i++)
            {
                rightvid = rightvids[i].FullName;
                leftvid = leftvids[i].FullName;
                gpsfile = gpsfiles[i].FullName;

                if (verbose==1)
                    Console.WriteLine("C# FileNames: " + settingsDir + " " + outputDir + " " + leftvid + " " + gpsfile);

                //Pass the filenames to the c++ functions
                int InitReturn = Initialize(settingsDir, settingsDir.Length, leftvid, leftvid.Length,
                    rightvid, rightvid.Length, gpsfile, gpsfile.Length, outputDir, outputDir.Length);

                if (verbose == 1)
                {
                    Console.WriteLine("Initilize return value : " + InitReturn);
                    Report();
                }

                //Setup the progress bar
                ProgressCallback callback = (value) => bar.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                    new Action(delegate() {bar.Value = value;} ));

                //***RUN THE ANALYSIS
                Console.WriteLine("Got this far4");
                int start_ret_val = Start(callback, verbose);
                if (verbose==1) Console.WriteLine("Start return value: " + start_ret_val);

                //Create the pothole array
                Pothole[] potArr = new Pothole[10000];
                Thread.Sleep(1000); //@todo Why sleep?

                if (start_ret_val > 0)
                {
                    //fill up the array 
                    ///@todo How does this impact the memory wastage?
                    potArr = GetPotholes(start_ret_val);

                    MessageBox.Show("Analysis completed");

                    //bar.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                      //                  new Action( delegate() { bar.Value = 0; } ));
                }
                else
                {
                    MessageBox.Show("Analysis returned with error code : " + start_ret_val); //@todo Add some interpretation here
                }

                Console.WriteLine("Got this far5");
            }                
        }

}

C ++函数从这里开始:

cv::Mat RunClassifier(cv::Mat& frame, cv::Mat& mask, std::vector<CvANN_MLP*>& anns, std::vector<int>& criteria,std::vector<float>& thresholds, Mat& final_certainty)
{
    //instantiate certainty matrix
    std::vector<Mat> indiv_certs;
    for (unsigned int i = 0; i < anns.size(); i++)
        indiv_certs.push_back(Mat::zeros(frame.size(), CV_32FC1) );
    Mat certainty = Mat::zeros(frame.size(), CV_32FC1);
    final_certainty = Mat::zeros(frame.size(), CV_32FC1);

    Mat final_image = frame.clone();
    Mat* individual_masks = new Mat[anns.size()]();
    for (unsigned int iter = 0; iter < anns.size();iter++)
    {
        individual_masks[iter] = Mat::zeros(frame.rows,frame.cols,CV_32F);
    }
    Mat final_mask = Mat::zeros(frame.rows,frame.cols,CV_32F);

    //Convert the image to HSV colorspace (You could probably save a bit more if you converted and normalised the frame to 32F beforehand
    // and not individually for each channel.
    Mat hsv;
    std::vector<Mat> hsv_channels;
    cvtColor(frame, hsv, CV_BGR2HSV);
    split(hsv, hsv_channels);

    Mat hue, value, saturation;
    hsv_channels.at(HUE).convertTo(hue, CV_32F);
    hue /= HUE_MAX;
    hue = 1- hue;   
    hsv_channels.at(SATURATION).convertTo(saturation, CV_32F);
    Mat sat_pure = saturation.clone();
    saturation /= SATURATION_MAX;
    hsv_channels.at(VALUE).convertTo(value, CV_32F);
    value /= VALUE_MAX;

    //loop through the anns 
    //Declare multithreading variables
    PCERT_DATA pCert_Array[3];
    DWORD dwThreadIdArray[3];
    HANDLE hThreadArray[3];

    for (unsigned int ann_iter = 0; ann_iter < anns.size(); ann_iter++)
    {
        //allocate memory for thread data
        pCert_Array[ann_iter] = (PCERT_DATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CERT_DATA) );

        bool fft_flag = FALSE;
        //Convert the image block according to the ann
        switch (criteria.at(ann_iter))
        {
            case HUE:
            {
                pCert_Array[ann_iter]->converted_frame = &hue;
                break;
            }
            case SATURATION:
            {
                pCert_Array[ann_iter]->converted_frame = &saturation;
                break;
            }
            case VALUE:
            {
                pCert_Array[ann_iter]->converted_frame = &value;;
                break;
            }
            case FREQUENCY:
            {
                pCert_Array[ann_iter]->converted_frame = &sat_pure;
                fft_flag = TRUE;
                break;
            }
            default:
            {
                return Mat();
            }
        }


        //assign data to memory
        pCert_Array[ann_iter]->ann = anns.at(ann_iter);
        pCert_Array[ann_iter]->certainty = &(indiv_certs[ann_iter]);

        pCert_Array[ann_iter]->mask = &mask;
        pCert_Array[ann_iter]->fft_flag = fft_flag;
        pCert_Array[ann_iter]->individual_mask =  &(individual_masks[ann_iter]);
        pCert_Array[ann_iter]->threshold = thresholds.at(ann_iter);

        //call CalculateCertainty
        hThreadArray[ann_iter] = CreateThread( 
            NULL,                   // default security attributes
            0,                      // use default stack size  
            ComputeCertainty,       // thread function name
            pCert_Array[ann_iter],          // argument to thread function 
            0,                      // use default creation flags 
            &dwThreadIdArray[ann_iter]);   // returns the thread identifier         
    }

    //wait for all the threads to stop computing
    WaitForMultipleObjects(anns.size(), hThreadArray, TRUE, INFINITE);

    //summing operation of certanties
    for (unsigned int i = 0; i < anns.size(); i++)
        certainty += indiv_certs[i];

    //AND all the various ANN outputs
    Mat temp = Mat::zeros(individual_masks[0].size(), individual_masks[0].type() );
    for (unsigned int i = 0; i < anns.size(); i++)
        temp += individual_masks[i];

    Mat temp_binary_mask = (temp == anns.size());
    temp = Mat::ones(individual_masks[0].size(), individual_masks[0].type() );
    temp.copyTo(final_mask, temp_binary_mask);

    cv::multiply(final_mask, certainty, final_certainty, 1.0/anns.size() );

    delete individual_masks;

    //deallocate threading memory used
    for(unsigned int i=0; i<anns.size(); i++)
    {
        CloseHandle(hThreadArray[i]);
        if(pCert_Array[i] != NULL)
        {
            HeapFree(GetProcessHeap(), 0, pCert_Array[i]);
            pCert_Array[i] = NULL;    // Ensure address is not reused.
        }
    }

    return final_mask;
}

1 个答案:

答案 0 :(得分:3)

  • 您是否尝试使用内存泄漏检测工具,例如Visual Leak Detector

  • 在下面的代码中,

    Mat* individual_masks = new Mat[anns.size()]();

    应使用operator delete[]删除

    ,以便delete[] individual_masks;

  • 此外,无论内存泄漏,都应该进行数组边界检查。

    for (unsigned int ann_iter = 0; ann_iter < anns.size(); ann_iter++) 
    { 
        //allocate memory for thread data 
        pCert_Array[ann_iter] = (PCERT_DATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CERT_DATA) );
    

    anns是输入参数,因此它的大小不是固定值,但在pCert_Array中声明PCERT_DATA pCert_Array[3];