使用SDL2渲染曼德博集合时出现重影及内存上涨问题求助
曼德博集合SDL2渲染问题:旧图像无法清除+内存占用上涨
我用C++写了曼德博集合渲染代码,通过SDL2库显示图像。设置按下W键时清除旧图像并以新参数渲染,但旧图像始终无法清除,且每次按W键内存占用都会上升,该怎么解决?
原代码
#include <complex> #include <iostream> #include <SDL.h> #include <chrono> #include <omp.h> using namespace std; int main(int argc, char** argv) { const int resolution= 2000; const int rows = resolution; const int cols = resolution; complex<long double> position; int dots[rows][cols]; for (int i = 0; i < rows; ++i) { for (int j = 0; j < cols; ++j) { dots[i][j] = 0; } } if (SDL_Init(SDL_INIT_VIDEO) < 0) { std::cerr << "SDL initialization failed: " << SDL_GetError() << std::endl; return 1; } const int screenWidth = cols * 1; // Adjust the window size as needed const int screenHeight = rows * 1; SDL_Window* window = SDL_CreateWindow("Mandelbrot set Visualization", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screenWidth, screenHeight, SDL_WINDOW_SHOWN); SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); SDL_Rect rect; long double startx = -2; long double endx = 2; long double starty = 2; long double endy = -2; long double stepx = (endx - startx) / (cols - 1); long double stepy = (endy - starty) / (rows - 1); rect.w = screenWidth / cols; rect.h = screenHeight / rows; int numThreads = 16; omp_set_num_threads(numThreads); #pragma omp parallel { int threadID = omp_get_thread_num(); // Get the thread ID #pragma omp for for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { long double real = startx + j * stepx; long double imag = starty + i * stepy; position = complex<long double>(real, imag); complex<long double> iterate(0, 0); int color = 0; for (int n = 0; n < 256; n++) { iterate = iterate * iterate + position; color++; if (abs(iterate) > 2) { dots[i][j] = color; break; } } } } } for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { SDL_SetRenderDrawColor(renderer, 0, dots[i][j], dots[i][j], 255); rect.x = j * (screenWidth / cols); rect.y = i * (screenHeight / rows); SDL_RenderFillRect(renderer, &rect); } } SDL_RenderPresent(renderer); // Main game loop bool quit = false; SDL_Event event; while (!quit) { while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { quit = true; } else if (event.type == SDL_KEYDOWN) { if (event.key.keysym.sym == SDLK_w) { // Zoom or change parameters, as needed cout << "loop start"; SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_RenderClear(renderer); long double decreaseAmountx = (abs(endx) + abs(startx)) / 20; long double decreaseAmounty = (abs(endy) + abs(starty)) / 20; endx -= decreaseAmountx; startx += decreaseAmountx; endy += decreaseAmounty; starty -= decreaseAmounty; stepx = (endx - startx) / (cols - 1); stepy = (endy - starty) / (rows - 1); // Render the Mandelbrot set with new parameters #pragma omp parallel { int threadID = omp_get_thread_num(); // Get the thread ID #pragma omp for for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { long double real = startx + j * stepx; long double imag = starty + i * stepy; position = complex<long double>(real, imag); complex<long double> iterate(0, 0); int color = 0; for (int n = 0; n < 256; n++) { iterate = iterate * iterate + position; color++; if (abs(iterate) > 2) { dots[i][j] = color; break; } } } } } for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { SDL_SetRenderDrawColor(renderer, 0, dots[i][j], dots[i][j], 255); rect.x = j * (screenWidth / cols); rect.y = i * (screenHeight / rows); SDL_RenderFillRect(renderer, &rect); } } cout << "Present"; SDL_RenderPresent(renderer); } else if (event.key.keysym.sym == SDLK_r) { // Trigger an SDL_QUIT event to exit the application SDL_Event quitEvent; quitEvent.type = SDL_QUIT; SDL_PushEvent(&quitEvent); } } } } // Cleanup and quit SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; }
问题原因及修复方案
1. 旧图像无法清除的核心原因
- 未更新集合内点的颜色值:原代码中,只有当点跳出曼德博集合(
abs(iterate)>2)时才会给dots[i][j]赋值,而集合内的点会保留上一次计算的旧值,导致绘制时旧图像残留。 - 渲染器同步问题:加速渲染器的
SDL_RenderClear操作可能未及时生效,导致清除操作被延后。
修复:
- 无论点是否在集合内,计算完成后都给
dots[i][j]赋值:// 替换原计算循环内的赋值逻辑 for (int n = 0; n < 256; n++) { iterate = iterate * iterate + position; color++; if (abs(iterate) > 2) { break; } } dots[i][j] = color; // 确保所有点都被更新 - 清除后强制刷新渲染器,确保清除操作完成:
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); if (SDL_RenderClear(renderer) != 0) { cerr << "SDL_RenderClear错误: " << SDL_GetError() << endl; } SDL_RenderFlush(renderer); // 强制完成清除操作
2. 内存占用上升的原因
- 栈溢出:
int dots[rows][cols]是在栈上分配的2000×2000的int数组(约16MB),远超默认栈大小(通常8MB),导致系统自动补充堆内存,引发内存占用异常上升。 - 线程竞争隐患:全局的
position变量被多线程共享,可能导致未定义行为和内存异常。
修复:
- 将
dots改为堆分配,使用vector自动管理内存:// 替换原int dots[rows][cols];及初始化代码 vector<vector<int>> dots(rows, vector<int>(cols, 0)); - 将
position移到循环内部,避免多线程共享:// 在并行循环内创建position,每个线程独立使用 complex<long double> position(real, imag);
优化后的关键代码片段
初始化部分
const int resolution= 2000; const int rows = resolution; const int cols = resolution; // 改用vector分配堆内存,避免栈溢出 vector<vector<int>> dots(rows, vector<int>(cols, 0));
W键处理逻辑
if (event.key.keysym.sym == SDLK_w) { cout << "loop start"; // 清除旧图像 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); if (SDL_RenderClear(renderer) != 0) { cerr << "SDL_RenderClear错误: " << SDL_GetError() << endl; } SDL_RenderFlush(renderer); // 更新参数 long double decreaseAmountx = (abs(endx) + abs(startx)) / 20; long double decreaseAmounty = (abs(endy) + abs(starty)) / 20; endx -= decreaseAmountx; startx += decreaseAmountx; endy += decreaseAmounty; starty -= decreaseAmounty; stepx = (endx - startx) / (cols - 1); stepy = (endy - starty) / (rows - 1); // 并行计算曼德博集合 #pragma omp parallel { #pragma omp for for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { long double real = startx + j * stepx; long double imag = starty + i * stepy; // 每个线程独立创建position,避免竞争 complex<long double> position(real, imag); complex<long double> iterate(0, 0); int color = 0; for (int n = 0; n < 256; n++) { iterate = iterate * iterate + position; color++; if (abs(iterate) > 2) { break; } } // 确保所有点都更新颜色值 dots[i][j] = color; } } } // 绘制新图像 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { SDL_SetRenderDrawColor(renderer, 0, dots[i][j], dots[i][j], 255); rect.x = j * (screenWidth / cols); rect.y = i * (screenHeight / rows); SDL_RenderFillRect(renderer, &rect); } } cout << "Present"; SDL_RenderPresent(renderer); }
内容的提问来源于stack exchange,提问作者Parsa Eslami
相关产品推荐
相关产品推荐

