关于OpenCL的C ++包装程序如何处理内存释放,我还找不到清晰的信息;任何指向此类引用的指针都将很棒。
我现在的特殊问题是,如果缓冲区超出了相应子缓冲区的范围,会发生什么?说,在这种情况下:
cl::Buffer *buf=new cl::Buffer;
*buf=cl::Buffer(context, CL_MEM_READ_WRITE, 1000);
cl_buffer_region reg={20, 50};
cl::Buffer sub=buf->createSubBuffer(CL_MEM_READ_WRITE, CL_BUFFER_CREATE_TYPE_REGION, ®);
delete buf;
分配的设备内存是否被释放,而buf指向无效的内存地址,还是程序等待sub也被销毁?
答案 0 :(得分:2)
用于OpenCL的C ++包装器使用由本地OpenCL API提供的引用计数(请参阅clRetainMemObject
和clReleaseMemObject
作为参考)来跟踪每个缓冲区。将它们视为已实现的这样的东西可能是准确的:
class cl::Buffer {
cl_mem buffer;
public:
Buffer(/*...*/) { buffer = clCreateBuffer(/*...*/);} //Implicit Retain
Buffer(Buffer const& o) {buffer = o.buffer; clRetainMemObject(buffer);}
~Buffer() {clReleaseMemObject(buffer);}
/*...*/
};
这对于子缓冲区也成立:它们使用与主缓冲区相同的内部引用计数机制({clCreateSubBuffer
被声明为implicitly call retain on the object产生缓冲区),因此它将被引用计数为很好,只要拥有的对象仍然存在,并且保持对原始缓冲区对象的引用,它就仍然有效。
此代码可能会有所帮助:
cl::Buffer do_stuff() {
cl::Buffer buffer{context, CL_MEM_READ_WRITE, 1000};
std::cout << "Ref Count: " << buffer.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
//Should print "Ref Count: 1" to console
cl::Buffer copy = buffer; //retain
std::cout << "Ref Count: " << buffer.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
//Should print "Ref Count: 2"
std::cout << "Ref Count: " << copy.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
//Should print "Ref Count: 2"
cl_buffer_region reg={20, 50};
cl::Buffer sub = buffer.createSubBuffer(CL_MEM_READ_WRITE, CL_BUFFER_CREATE_TYPE_REGION, ®); //retain
std::cout << "Ref Count: " << buffer.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
//Should print "Ref Count: 3"
std::cout << "Ref Count: " << sub.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
//I believe it prints "Ref Count: 1", but if it inherits the main buffer's reference count,
//then it'll print "Ref Count: 3" instead. Not sure what the actual specification is
return sub;
//release buffer
//release copy
}
void outer_code() {
cl::Buffer subBuffer = do_stuff();
//Should print "Ref Count: 1", "Ref Count: 2", "Ref Count: 2", "Ref Count: 3", "Ref Count: 1", in order
std::cout << "Ref Count: " << subBuffer.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
//Should print "Ref Count: 1"
//End of scope: release subBuffer
}
我们还可以确认,使用保留/释放语义,直到子缓冲区也被删除之前,原始缓冲区将不会被删除,因为规范这样说:
在
memobj
参考计数变为零并且命令排队等待在 使用memobj
的命令队列已完成,存储对象被删除。 如果memobj
是一个缓冲区对象,则在删除与memobj关联的所有子缓冲区对象之前,无法删除memobj
。使用此功能来释放不是由引用获得的引用。创建对象或调用clRetainMemObject
会导致未定义的行为— clReleaseMemObject ,OpenCL 2.0规范,pg. 156
因此,在正确实现C ++ OpenCL包装器的假设下,可以肯定地说,在删除原始缓冲区对象的所有者之后,子缓冲区将继续存在,因为将使用keep /删除原始缓冲区释放语义,并一直保持到删除子缓冲区为止。