Qt结合OpenGL场景下如何高效删除大量指定图形?
问题根因分析
你的代码耗时核心来自两个O(n)操作嵌套,最终产生了O(n²)的时间复杂度,百万级数据下运算量指数级上涨:
alldrawerlist.indexOf(p)是线性查找逻辑,每次执行都需要遍历整个alldrawerlist才能匹配到对应指针的索引alldrawerlist.removeAt(index)删除非末尾元素时,需要将索引后的所有元素整体向前移动,也是O(n)时间开销
两类操作嵌套在百万次循环中,嵌入式设备性能不足以支撑如此大的运算量,必然出现卡顿。
优化方案
1. 单次遍历过滤+批量删除,时间复杂度降至O(n)
先将待删除的指针存入QSet实现O(1)存在性判断,随后仅遍历一次全量Drawable列表,过滤出需要保留的对象重建全量列表,同时批量释放待删除对象,完全避免重复查找和列表元素移动的开销,优化后代码如下:
void deleteDrawable() { if(need_to_delete_drawerlist.isEmpty()) return; // 转存为集合实现O(1)查找 QSet<Drawable*> delete_set(need_to_delete_drawerlist.begin(), need_to_delete_drawerlist.end()); QList<Drawable*> retained_list; // 预分配内存,避免动态扩容开销 retained_list.reserve(alldrawerlist.size() - need_to_delete_drawerlist.size()); for (auto drawable : alldrawerlist) { if (delete_set.contains(drawable)) { delete drawable; } else { retained_list.append(drawable); } } // 替换原全量列表 alldrawerlist.swap(retained_list); need_to_delete_drawerlist.clear(); }
2. 新增删除标记简化逻辑
如果业务允许,可以直接在Drawable类中新增删除标记位,不需要单独维护need_to_delete_drawerlist,需要删除线条时直接给对应对象打标记即可,进一步降低维护开销:
class Drawable : protected QOpenGLExtraFunctions { public: bool is_to_delete = false; // 其余原有逻辑 ...... }
删除函数可简化为:
void deleteDrawable() { QList<Drawable*> retained_list; retained_list.reserve(alldrawerlist.size()); for (auto drawable : alldrawerlist) { if (drawable->is_to_delete) { delete drawable; } else { retained_list.append(drawable); } } alldrawerlist.swap(retained_list); }
3. 额外性能优化点
- 替换
QList为QVector:QVector采用连续内存存储,遍历效率远高于QList,百万级元素下性能提升尤为明显 - 批量释放OpenGL资源:如果
Drawable持有VBO、VAO等OpenGL资源,不要在析构函数中单个释放,可以将待释放的资源ID攒齐后批量调用glDeleteBuffers等接口,OpenGL批量操作的性能远优于多次单次操作 - 分帧分批删除:如果单次需要删除的元素量极大,可以将删除操作分散到多个渲染帧的空闲间隙执行,每帧仅删除固定数量(例如1000个)的对象,避免阻塞渲染主线程导致卡顿
- 引入对象池复用Drawable:避免频繁new/delete小对象带来的堆分配开销和内存碎片,嵌入式设备上内存碎片会进一步拖慢后续内存操作速度,对象池可大幅降低这类开销
内容的提问来源于stack exchange,提问作者Jackey
相关产品推荐
相关产品推荐

