调用free后内存未释放,malloc时内存持续上涨问题排查
内存泄漏排查:SDL2子弹对象未正确释放问题
我用SDL2和SDL_image开发飞船射击程序,按空格键发射PNG格式子弹,子弹向右移动。屏幕所有元素都是object结构体实例,存储在链表中;create_ent函数负责为新对象分配内存并完成初始化,move_ents函数根据对象的xvector和yvector属性移动所有对象,同时检测对象是否超出屏幕范围,若超出则释放对象并维护链表结构。
通过任务管理器监测内存使用情况发现:运行move_ents函数后内存并未释放,且每次调用create_ent时内存持续上涨。已知free后的内存可能会保留给当前程序复用而非直接还给操作系统,但这种持续上涨的情况让我疑惑:是任务管理器显示问题,还是我的内存释放代码存在错误?Visual Studio未给出任何错误提示。
相关代码
#include <stdio.h> #include <SDL.h> #include <SDL_ttf.h> #include <SDL_image.h> #define WINDOW_WIDTH 1280 #define WINDOW_HEIGHT 720 #define TARGET_FPS 60 struct object { SDL_Surface* surface; SDL_Texture* texture; SDL_Rect rect; SDL_Point center; int is_ship; int inside; long float x; long float y; float w; float h; long float xvector; long float yvector; long float mass; long float forcex; long float forcey; float rot_speed; double angle; struct object* next; }; void create_ent(SDL_Renderer* renderer, struct object* p, char* img_path, long float x, long float y, float w, float h, long float xvector, long float yvector, long float mass, double angle, int ship) { struct object* new = malloc(sizeof(struct object)); while (p->next != NULL) p = p->next; p->next = new; new->surface = IMG_Load(img_path); if (!(new->surface)) printf("Dammit! An image wasn't found."); new->texture = SDL_CreateTextureFromSurface(renderer, new->surface); new->x = x; new->y = y; new->w = w; new->h = h; new->xvector = xvector; new->yvector = yvector; new->mass = mass; new->forcex = 0; new->forcey = 0; new->inside = 1; new->angle = angle; new->center = (SDL_Point){ w / 2, h / 2 }; new->is_ship = ship; new->next = NULL; } void move_ents(struct object* p) { struct object* temp; while (p->next != NULL) { if ((p->next)->inside == 0) { if ((p->next)->next == NULL) { free(p->next); p->next = NULL; break; } else { temp = (p->next)->next; free(p->next); p->next = temp; } } p = p->next; if (!(p->is_ship)) if ((p->x > WINDOW_WIDTH + p->w / 2) || (p->y > WINDOW_HEIGHT + p->h / 2) || (p->x < 0 - p->w / 2) || (p->y < 0 - p->h / 2)) { p->inside = 0; printf("object outside of window"); } p->xvector += (p->forcex / p->mass); p->yvector += (p->forcey / p->mass); p->x += p->xvector; p->y += p->yvector; } } int main(void) { while (SDL_PollEvent(&event) != 0) { switch (event.type) { case SDL_QUIT: quit = 1; break; case SDL_KEYUP: switch (event.key.keysym.sym) { case SDLK_SPACE: create_ent(renderer, head, "allmine/Laser/laser.png", ship->x + 10, ship->y + 10, 5, 25, 10, 0, 1, ship->angle, 0); break; case SDLK_RIGHT: rightpressed = 0; break; case SDLK_LEFT: leftpressed = 0; break; case SDLK_UP: uppressed = 0; break; default: break; } break; case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_RIGHT: rightpressed = 1; break; case SDLK_LEFT: leftpressed = 1; break; case SDLK_UP: uppressed = 1; break; default: break; } default: break; } } if (rightpressed) ship->angle += 5; else if (leftpressed) ship->angle -= 5; draw_ents(renderer, head); apply_forces(head, 10000); move_ents(head); SDL_RenderPresent(renderer); // Tickrate frameStart = SDL_GetTicks(); frameTime = SDL_GetTicks() - frameStart; if (frameTime < 1000 / TARGET_FPS) SDL_Delay((1000 / TARGET_FPS) - frameTime); } }
问题分析与修复方案
1. 核心问题:SDL资源未释放
你的object结构体包含SDL_Surface*和SDL_Texture*,这两类资源属于SDL的内核对象,必须通过专用接口释放,直接free结构体只会释放结构体本身的内存,而SDL分配的GPU/CPU资源会永久泄漏,这是内存持续上涨的主要原因。
2. 链表释放逻辑漏洞
原代码在释放节点后直接break或移动指针,会导致后续需要释放的节点被跳过,无法完成完整的链表清理;同时释放节点后的指针移动逻辑错误,可能跳过正常节点的检测和移动操作。
3. 任务管理器显示问题
确实,free不会立刻将内存归还给操作系统,而是留作程序后续复用,但内存持续上涨说明肯定存在真实泄漏,并非单纯显示问题,不需要改用realloc。
具体修复代码
修正move_ents函数(先释放SDL资源,再释放结构体)
void move_ents(struct object* p) { while (p != NULL && p->next != NULL) { struct object* current = p->next; // 检测是否需要释放 if (current->inside == 0) { // 先释放SDL资源 SDL_FreeSurface(current->surface); SDL_DestroyTexture(current->texture); // 再释放结构体内存并维护链表 p->next = current->next; free(current); // 不移动p,继续检查新的p->next continue; } // 非飞船对象的边界检测 if (!current->is_ship) { if ((current->x > WINDOW_WIDTH + current->w / 2) || (current->y > WINDOW_HEIGHT + current->h / 2) || (current->x < 0 - current->w / 2) || (current->y < 0 - current->h / 2)) { current->inside = 0; printf("object outside of window"); // 留到下次循环处理释放,保持逻辑一致 p = current; continue; } } // 更新速度与位置 current->xvector += (current->forcex / current->mass); current->yvector += (current->forcey / current->mass); current->x += current->xvector; current->y += current->yvector; p = current; } }
修正create_ent函数的错误处理(图片加载失败时释放已分配内存)
void create_ent(SDL_Renderer* renderer, struct object* p, char* img_path, long float x, long float y, float w, float h, long float xvector, long float yvector, long float mass, double angle, int ship) { struct object* new = malloc(sizeof(struct object)); if (!new) { printf("Failed to allocate memory for new object"); return; } while (p->next != NULL) p = p->next; new->surface = IMG_Load(img_path); if (!(new->surface)) { printf("Dammit! An image wasn't found."); // 加载失败时释放已分配的结构体 free(new); p->next = NULL; return; } new->texture = SDL_CreateTextureFromSurface(renderer, new->surface); if (!new->texture) { printf("Failed to create texture from surface"); SDL_FreeSurface(new->surface); free(new); p->next = NULL; return; } // 其他初始化代码... new->x = x; new->y = y; new->w = w; new->h = h; new->xvector = xvector; new->yvector = yvector; new->mass = mass; new->forcex = 0; new->forcey = 0; new->inside = 1; new->angle = angle; new->center = (SDL_Point){ w / 2, h / 2 }; new->is_ship = ship; new->next = NULL; p->next = new; }
内容的提问来源于stack exchange,提问作者Margorp13
相关产品推荐
相关产品推荐

