原文
Automatic Memory Management OpenCV handles all the memory automatically.
First of all, std::vector, cv::Mat, and other data structures used by the functions and methods have destructors that deallocate the underlying memory buffers when needed. This means that the destructors do not always deallocate the buffers as in case of Mat. They take into account possible data sharing. A destructor decrements the reference counter associated with the matrix data buffer. The buffer is deallocated if and only if the reference counter reaches zero, that is, when no other structures refer to the same buffer. Similarly, when a Mat instance is copied, no actual data is really copied. Instead, the reference counter is incremented to memorize that there is another owner of the same data. There is also the cv::Mat::clone method that creates a full copy of the matrix data. See the example below:
// create a big 8Mb matrix// create another header for the same matrix;// this is an instant operation, regardless of the matrix size.Mat B = A;// create another header for the 3-rd row of A; no data is copied either// now create a separate copy of the matrix// copy the 5-th row of B to C, that is, copy the 5-th row of A// to the 3-rd row of A.// now let A and D share the data; after that the modified version// of A is still referenced by B and C.A = D;// now make B an empty matrix (which references no memory buffers),// but the modified version of A will still be referenced by C,// despite that C is just a single row of the original AB.release();// finally, make a full copy of C. As a result, the big modified// matrix will be deallocated, since it is not referenced by anyoneC = C.clone();
你看到使用Mat
和其他基本数据结构是很简单的。但是对于高层次的类或者是那些在设计时没有考虑到自动内存管理的用户自定义数据类型呢?对于这些情况,OpenCV 提供了 cv::Ptr
模板类,它类似于 C++11 中的 std::shared_ptr
。因此,你可以不用普通的指针,而是使用 cv::Ptr
:
T* ptr = new T(...);
你会看见:
Ptr<T> ptr(new T(...));
或者:
Ptr<T> ptr = makePtr<T>(...);
Ptr<T>
封装了一个指向类型 T
实例的指针以及一个与该指针关联的引用计数。有关详细信息,请参阅 cv::Ptr
的描述。
说明
自动内存管理
在OpenCV中,像std::vector
、cv::Mat
这样的数据结构,其内部实现会自动管理内存。这意味着当这些对象不再被使用时,它们会自动释放所占用的内存。具体来说,这些数据结构实现了智能引用计数机制。
引用计数机制
-
共享内存:当一个
cv::Mat
对象被创建时,它会拥有一个内存缓冲区。如果另一个cv::Mat
对象指向同一块内存,那么这块内存的引用计数就会增加。这意味着没有实际的数据复制发生,只有引用计数的增加。 -
释放内存:当一个
cv::Mat
对象被销毁时,其内部的析构函数会减少这块内存的引用计数。只有当引用计数降到零时,这块内存才会被释放。
示例代码解释
让我们来看一下给定的代码示例:
-
Mat A(1000, 1000, CV_64F);
- 创建了一个大小为1000x1000的双精度浮点数矩阵
A
。
- 创建了一个大小为1000x1000的双精度浮点数矩阵
-
Mat B = A;
- 创建一个新的
Mat
对象B
,它指向与A
相同的内存缓冲区。此时引用计数增加到2。
- 创建一个新的
-
Mat C = B.row(3);
C
是一个指向B
第三行的新Mat
对象。这里C
并不是一个完整的矩阵,而是一个视图(view)。
-
Mat D = B.clone();
D
是一个B
的完整副本。这意味着D
拥有自己的内存缓冲区,与A
和B
不共享内存。
-
B.row(5).copyTo(C);
- 将
B
的第五行复制到C
中,即修改了A
的第三行。
- 将
-
A = D;
- 此时
A
指向了D
的内存缓冲区,A
和D
现在共享同一个内存。
- 此时
-
B.release();
B
释放其对内存的引用,引用计数减1。但由于C
仍然指向A
的一部分,所以内存不会被释放。
-
C = C.clone();
C
创建了自己的内存副本,因此原来的内存不再被任何对象引用,最终会被释放。
使用cv::Ptr
管理内存
除了基本数据结构之外,对于用户定义的数据类型或高级类,OpenCV提供了cv::Ptr
模板类来帮助管理内存。cv::Ptr
类似于C++11中的std::shared_ptr
,它封装了一个指针和一个引用计数。这样,当最后一个指向某个对象的cv::Ptr
实例被销毁时,对象本身也会被自动删除。
例如,可以使用cv::Ptr
来替代原始指针:
1Ptr<T> ptr(new T(...));
或者使用makePtr<T>
工厂函数:
1Ptr<T> ptr = makePtr<T>(...);
这种方式使得内存管理更加安全且易于维护。