在没有 Pdb 文件的 Visual Studio 中调试(C++ 访问冲突)
Debugging in Visual Studio without Pdb files (C++ Access Voilation)
我使用 Cmake 和 visual studio 构建了 OpenCV 二进制文件 (.dll),它生成了 .pdb 文件,帮助我找到了代码中的问题(部分!)
此崩溃是如何造成的。 .
我正在使用一种软件,我们可以通过它为任何特定程序设置互联网下载速度限制(传输速率)。
现在,如果我将 IP 摄像机连接到下面的代码,我注意到我的应用程序需要大约 100Kb/s 的互联网使用率(传输速率)——只有这样我才能无缝观看直播。
假设我将我的应用程序互联网使用率减少(设置)为 10Kb/s [这就是崩溃背后的原因]
在这种情况下,我应该能够在 4+ 秒内看到一次新帧。
我收到访问冲突错误,可能是因为 (cap>>img;
) cap 试图到达 ram 中的某个位置并获取框架,但还没有框架,因为由于网速低,它仍在下载.
很明显,指针正在到达 ram 中的某个位置以获取尚未出现的帧。
一些有趣的行为。 . .
Void OpenCamera()
{
VideoCapture cap("http://192.168.1.3:8080/video?x.xmjpeg");
Mat img;
while(true)
{
try
{
if(cap.isOpened()) //also tried grab + retrieve, crashes at grab
cap>>img; //code crashes here
}
catch(...)
{
cout<<"Camera Disconnected"<<endl;
}
}
}
如果我在同一个 class 中使用整个代码(在同一个头文件中),则完全没有问题(新帧在 4 秒后显示而不会导致程序崩溃)但是如果我将代码到一个单独的 class(不同的头文件),然后调用函数从 class 对象打开相机,然后它崩溃 if 网速变慢了.
奇怪的行为 - 如果我一步一步调试,它永远不会崩溃!
当我使用 ffmpeg 构建 opencv 库时,我得到的 .pdb 文件仅为 opencv (opencv_world310.pdb) - 所以使用调用堆栈进行调试没有问题
但我没有得到 ffmpeg 的 pdb(因为 Opencv_ffmpeg.dll 是预编译的,这就是它崩溃的地方)
因此它越来越难调试,building ffmpeg 不生成 pdb 文件因为它是使用 MSYS 构建的
那么是否可以用我们现有的进行调试?
我包括来自 visual studio 调试的快照,
一些有助于理解的变量:
typedef int (*CvGrabFrame_Plugin)( void* capture_handle ); [cap_ffmpeg_api.cpp]
protected: void* ffmpegCapture; [cap_ffmpeg.cpp]
static CvGrabFrame_Plugin icvGrabFrame_FFMPEG_p = 0; [cap_ffmpeg.cpp]
Exception thrown at 0x0A0AF6F0 (opencv_ffmpeg310.dll) in Sample.exe:
0xC0000005: Access violation reading location 0x00000020. If there is
a handler for this exception, the program may be safely continued.
在源代码中,我在下面的行中包含并编译并在项目中使用它 - 没有工作,再次崩溃!
if(ffmpegCapture)
- 空指针检查
我们可以在 [cap_ffmpeg.cpp] 中的第 214 行进行一些更改以避免崩溃吗?
其他头文件都只是一个文件夹了。
更新: 我注意到当我限制互联网消费速度时程序立即崩溃。我正在使用 C++/Cli(winforms,target dot net Framework = 4.6),我有 CameraClass(在单独的头文件中)和主要函数(单独的头文件)
Main 函数具有以下代码
CameraClass ^CC = gcnew CameraClass();
CC->OpenCamera();
我无法在托管 class 中创建非托管对象类型,因此我将本机类型(Opencv 变量)放入单独的命名空间中,如下所示,以便我可以在此 class 中使用。可能我必须使用内部指针?
#pragma once
#include"opencv2\opencv.hpp"
#include <msclr\marshal_cppstd.h>
namespace SampleApp{
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Threading;
using namespace System::IO;
using namespace std;
namespace
{
cv::VideoCapture cap[5]; //max 5 instance for this class
cv::Mat image[5];
cv::IplImage pic1[5];
cv::IplImage *pic2[5];
}
public ref class CamWindow : public WeifenLuo::WinFormsUI::Docking::DockContent
{
public: CamWindow(void)
{
InitializeComponent();
}
Void OpenCamera()
{
}
.
.
.
.
};
}
.net 内存处理和 C++ 内存处理之间肯定存在冲突?
您可以声明一个非托管的 class。从托管 class.
获得指向它的指针
public class OpenCVClass
{
public:
Void OpenCamera()
{
VideoCapture cap("http://192.168.1.3:8080/video?x.xmjpeg");
Mat img;
while(true)
{
try
{
if(cap.isOpened())
cap>>img;
}
catch(...)
{
cout<<"Camera Disconnected"<<endl;
}
}
}
public ref class managed
{
public:
managed(){}
~managed(){}
static OpenCVClass* unmanaged = new OpenCVClass();
unmanaged->OpenCVClass();
};
}
如果 dll 是在 MSYS 上构建的,您可以使用 addr2line command 将 DLL 中的地址转换为源代码行,或者在托管 class 的函数中使用非托管变量。
我使用 Cmake 和 visual studio 构建了 OpenCV 二进制文件 (.dll),它生成了 .pdb 文件,帮助我找到了代码中的问题(部分!)
此崩溃是如何造成的。 .
我正在使用一种软件,我们可以通过它为任何特定程序设置互联网下载速度限制(传输速率)。
现在,如果我将 IP 摄像机连接到下面的代码,我注意到我的应用程序需要大约 100Kb/s 的互联网使用率(传输速率)——只有这样我才能无缝观看直播。 假设我将我的应用程序互联网使用率减少(设置)为 10Kb/s [这就是崩溃背后的原因] 在这种情况下,我应该能够在 4+ 秒内看到一次新帧。
我收到访问冲突错误,可能是因为 (cap>>img;
) cap 试图到达 ram 中的某个位置并获取框架,但还没有框架,因为由于网速低,它仍在下载.
很明显,指针正在到达 ram 中的某个位置以获取尚未出现的帧。
一些有趣的行为。 . .
Void OpenCamera()
{
VideoCapture cap("http://192.168.1.3:8080/video?x.xmjpeg");
Mat img;
while(true)
{
try
{
if(cap.isOpened()) //also tried grab + retrieve, crashes at grab
cap>>img; //code crashes here
}
catch(...)
{
cout<<"Camera Disconnected"<<endl;
}
}
}
如果我在同一个 class 中使用整个代码(在同一个头文件中),则完全没有问题(新帧在 4 秒后显示而不会导致程序崩溃)但是如果我将代码到一个单独的 class(不同的头文件),然后调用函数从 class 对象打开相机,然后它崩溃 if 网速变慢了.
奇怪的行为 - 如果我一步一步调试,它永远不会崩溃!
当我使用 ffmpeg 构建 opencv 库时,我得到的 .pdb 文件仅为 opencv (opencv_world310.pdb) - 所以使用调用堆栈进行调试没有问题 但我没有得到 ffmpeg 的 pdb(因为 Opencv_ffmpeg.dll 是预编译的,这就是它崩溃的地方)
因此它越来越难调试,building ffmpeg 不生成 pdb 文件因为它是使用 MSYS 构建的
那么是否可以用我们现有的进行调试?
我包括来自 visual studio 调试的快照, 一些有助于理解的变量:
typedef int (*CvGrabFrame_Plugin)( void* capture_handle ); [cap_ffmpeg_api.cpp]
protected: void* ffmpegCapture; [cap_ffmpeg.cpp]
static CvGrabFrame_Plugin icvGrabFrame_FFMPEG_p = 0; [cap_ffmpeg.cpp]
Exception thrown at 0x0A0AF6F0 (opencv_ffmpeg310.dll) in Sample.exe: 0xC0000005: Access violation reading location 0x00000020. If there is a handler for this exception, the program may be safely continued.
在源代码中,我在下面的行中包含并编译并在项目中使用它 - 没有工作,再次崩溃!
if(ffmpegCapture)
- 空指针检查
我们可以在 [cap_ffmpeg.cpp] 中的第 214 行进行一些更改以避免崩溃吗?
其他头文件都只是一个文件夹了。
更新: 我注意到当我限制互联网消费速度时程序立即崩溃。我正在使用 C++/Cli(winforms,target dot net Framework = 4.6),我有 CameraClass(在单独的头文件中)和主要函数(单独的头文件)
Main 函数具有以下代码
CameraClass ^CC = gcnew CameraClass();
CC->OpenCamera();
我无法在托管 class 中创建非托管对象类型,因此我将本机类型(Opencv 变量)放入单独的命名空间中,如下所示,以便我可以在此 class 中使用。可能我必须使用内部指针?
#pragma once
#include"opencv2\opencv.hpp"
#include <msclr\marshal_cppstd.h>
namespace SampleApp{
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Threading;
using namespace System::IO;
using namespace std;
namespace
{
cv::VideoCapture cap[5]; //max 5 instance for this class
cv::Mat image[5];
cv::IplImage pic1[5];
cv::IplImage *pic2[5];
}
public ref class CamWindow : public WeifenLuo::WinFormsUI::Docking::DockContent
{
public: CamWindow(void)
{
InitializeComponent();
}
Void OpenCamera()
{
}
.
.
.
.
};
}
.net 内存处理和 C++ 内存处理之间肯定存在冲突?
您可以声明一个非托管的 class。从托管 class.
获得指向它的指针public class OpenCVClass
{
public:
Void OpenCamera()
{
VideoCapture cap("http://192.168.1.3:8080/video?x.xmjpeg");
Mat img;
while(true)
{
try
{
if(cap.isOpened())
cap>>img;
}
catch(...)
{
cout<<"Camera Disconnected"<<endl;
}
}
}
public ref class managed
{
public:
managed(){}
~managed(){}
static OpenCVClass* unmanaged = new OpenCVClass();
unmanaged->OpenCVClass();
};
}
如果 dll 是在 MSYS 上构建的,您可以使用 addr2line command 将 DLL 中的地址转换为源代码行,或者在托管 class 的函数中使用非托管变量。