我的程序在屏幕上绘制一个可以移动的 3D 立方体。当程序刚刚运行或尝试移动立方体时,随着时间的推移,会出现一些内存泄漏。另外,每当立方体靠近屏幕并“超过它”时,我都会遇到内存使用量的巨大峰值,有时它会达到疯狂的值,超过 GBS 的内存,甚至导致我的计算机死机。我见过有人说 sdl2 库本身存在一些小泄漏,应该忽略它们,但这有点太多了 :o.
代码如下:
#define SDL_MAIN_HANDLED
#include <stdio.h>
#include <stdbool.h>
#include <SDL2/SDL.h>
const int gWidth = 640;
const int gHeight = 480;
const float moveSpeed = 5.0f;
const int fl = 300;
const int centerX = gWidth / 2;
const int centerY = gHeight / 2;
const int centerZ = 1000;
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
struct Vector3 {
float x; float y; float z;
};
bool init() {
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
printf("SDL Erorr: %s", SDL_GetError());
return false;
}
gWindow = SDL_CreateWindow("hi", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, gWidth, gHeight, 0);
if(gWindow == NULL) {
printf("SDL Erorr: %s", SDL_GetError());
return false;
}
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_PRESENTVSYNC);
if(gWindow == NULL) {
printf("SDL Erorr: %s", SDL_GetError());
return false;
}
return true;
}
void close() {
SDL_DestroyRenderer(gRenderer);
SDL_DestroyWindow(gWindow);
SDL_Quit();
}
// moves 8 points
void translateModel(struct Vector3* input, float x, float y, float z) {
for(int i = 0; i < 8; i++) {
input[i].x += x;
input[i].y += y;
input[i].z += z;
}
}
// project 3D point onto the 2D screen
SDL_Point projectPoint(struct Vector3 input) {
float perspective = 1.0f;
float distance = fl + input.z + centerZ;
// comparing floating points
if(distance > 1 || distance < -1) {
perspective = fl / distance;
}
SDL_Point p;
// + centerX makes origin sit in the middle of the screen
p.x = input.x * perspective + centerX;
p.y = input.y * perspective + centerY;
return p;
}
// connects 8 points to form a cube
void drawCube(struct Vector3* input) {
for(int i = 0; i < 4; i++) {
SDL_Point p0 = projectPoint(input[i]); // 0 1 1 2 2 3 3 0
SDL_Point p1 = projectPoint(input[(i + 1) % 4]);
SDL_RenderDrawLine(gRenderer, p0.x, p0.y, p1.x, p1.y);
}
for(int i = 0; i < 4; i++) {
SDL_Point p0 = projectPoint(input[i + 4]);
SDL_Point p1 = projectPoint(input[(i + 1) % 4 + 4]);
SDL_RenderDrawLine(gRenderer, p0.x, p0.y, p1.x, p1.y);
}
for(int i = 0; i < 4; i++) {
SDL_Point p0 = projectPoint(input[i]);
SDL_Point p1 = projectPoint(input[(i + 4)]);
SDL_RenderDrawLine(gRenderer, p0.x, p0.y, p1.x, p1.y);
}
}
void draw(struct Vector3* input) {
SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(gRenderer);
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
drawCube(input);
SDL_RenderPresent(gRenderer);
}
int main() {
// initialize SDL stuff
init();
bool isRunning = true;
SDL_Event e;
const Uint8* gKeyStates = SDL_GetKeyboardState(NULL);
struct Vector3 points[8] = {
[0] = {-150, -150, 150},
[1] = {150, -150, 150},
[2] = {150, 150, 150},
[3] = {-150, 150, 150},
[4] = {-150, -150, -150},
[5] = {150, -150, -150},
[6] = {150, 150, -150},
[7] = {-150, 150, -150},
};
while(isRunning) {
SDL_PollEvent(&e);
if(e.type == SDL_QUIT) {
return false;
}
if(gKeyStates[SDL_SCANCODE_LEFT]) { // add "tickrate" so that speed matches with diffrent frame rates
translateModel(points, -moveSpeed, 0, 0);
}
if(gKeyStates[SDL_SCANCODE_RIGHT]) {
translateModel(points, moveSpeed, 0, 0);
}
if(gKeyStates[SDL_SCANCODE_UP]) {
translateModel(points, 0, 0, -moveSpeed);
}
if(gKeyStates[SDL_SCANCODE_DOWN]) {
translateModel(points, 0, 0, moveSpeed);
}
draw(points);
}
close();
return 0;
}
我尝试使用 porgram dr 内存,它产生了这个
Error #1: UNADDRESSABLE ACCESS beyond top of stack: reading 0x0000002b24fff860-0x0000002b24fff868 8 byte(s)
# 0 .text
# 1 _pei386_runtime_relocator
# 2 __tmainCRTStartup
# 3 .l_start
# 4 KERNEL32.dll!BaseThreadInitThunk
Note: @0:00:00.253 in thread 6472
Note: 0x0000002b24fff860 refers to 776 byte(s) beyond the top of the stack 0x0000002b24fffb68
Note: instruction: or $0x0000000000000000 (%rcx) -> (%rcx)
Error #2: UNINITIALIZED READ: reading 0x0000002b24ffeb7c-0x0000002b24ffeb80 4 byte(s) within 0x0000002b24ffeb78-0x0000002b24ffeb80
# 0 system call NtGdiOpenDCW parameter value #5
# 1 gdi32full.dll!hdcCreateDCW +0xb1 (0x00007ff846b2f8e2 <gdi32full.dll+0x1f8e2>)
# 2 GDI32.dll!bCreateDCW
# 3 GDI32.dll!CreateDCW
# 4 SDL2.dll!? +0x0 (0x00007ff8042e484e <SDL2.dll+0x12484e>)
# 5 SDL2.dll!? +0x0 (0x00007ff8042e4bd3 <SDL2.dll+0x124bd3>)
# 6 USER32.dll!_ClientMonitorEnumProc
# 7 SDL2.dll!? +0x0 (0x00007ff8042e4e57 <SDL2.dll+0x124e57>)
# 8 SDL2.dll!? +0x0 (0x00007ff8042e8546 <SDL2.dll+0x128546>)
# 9 SDL2.dll!? +0x0 (0x00007ff8042aeea0 <SDL2.dll+0xeeea0>)
#10 SDL2.dll!? +0x0 (0x00007ff8041c16e7 <SDL2.dll+0x16e7>)
#11 init
#12 main
Note: @0:00:01.236 in thread 6472
整个日志文件很长,所以我只包含前两个错误
在“糟糕”的相机位置期间,确保您传入的线条
SDL_RenderDrawLine()
不是超长(如数百万或数十亿像素)。
如果它们超长并且 SDL 处于
SDL_RENDERLINEMETHOD_POINTS
模式,它将达到 SDL_render.c:RenderDrawLineBresenham()
,其内部分配与线的长度(以像素为单位)成比例。
处理超长线路的一些选项:
SDL_RenderDrawLine()
SDL_RenderDrawLine()
SDL_RENDER_LINE_METHOD
提示设置为 2
或 3
,以便渲染器代码避免 RenderDrawLineBresenham()