我的程序在屏幕上画了一个3D立方体,你可以移动它.当程序刚刚运行或我试图移动多维数据集时,随着时间的推移,会有一些内存泄漏.

此外,每当立方体接近屏幕并超过它时,我就会体验到内存使用量的巨大峰值,有时会超过GB的RAM,以至于我的计算机死机.

我看到有人说sdl2库本身有一些小漏洞,应该忽略它们,但这有点太过分了:O.

screenshot of cube rendered with perspective

代码如下:

#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;
}

我试着使用Dr.Memory,它产生了这个结果:

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

整个日志(log)文件很长,所以我只包含了前两个错误.

推荐答案

在相机位置不好的时候,要确保你传到SDL_RenderDrawLine()的线条不会太长(比如数百万或数十亿像素).

如果它们是超长的,而SDL处于SDL_RENDERLINEMETHOD_POINTS模式,它将达到SDL_render.c:RenderDrawLineBresenham(),这将进行内部分配,与以像素为单位的行的长度成比例.

以下是处理超长队伍的几种 Select :

  • 在呼叫SDL_RenderDrawLine()之前,将线裁剪到渲染器范围
  • 向SDL提交错误以在SDL_RenderDrawLine()内进行裁剪
  • SDL_RENDER_LINE_METHOD提示设置为23,以便呈现器代码避免RenderDrawLineBresenham()

C++相关问答推荐

有什么方法可以检测SunOS上的SparcWorks吗?

如何避免重新分配指针数组时,我们从一开始就不知道确切的大小

字符串令牌化xpath表达式

VS代码C/C++扩展intellisense无法检测环境特定函数'

如何设置指针指向在函数中初始化的复合文字中的整数?

C:fopen是如何实现二进制模式和文本模式的?

文件权限为0666,但即使以超级用户身份也无法打开

Flose()在Docker容器中抛出段错误

防止规范模式在C++中 echo 特殊字符

如何在C中只对字符串(包含数字、单词等)中的数字进行重复操作?

我在反转双向链表时遇到问题

按长度对argv中的单词进行排序

如何在双向表中实现线程安全,每个条目仅使用4位,同时避免任何全局锁?

GetText不适用于包含国际字符的帐户名称

从CentOS 7到Raspberry PI 2B的交叉编译-无法让LIBC和System Include标头一起工作

Leet代码运行时错误:代码不会在Leet代码上编译,而是在其他编译器中编译,如netbeans和在线编译器

模仿 memmove 的行为

添加/删除链表中的第一个元素

在 C/C++ 中原子按位与字节的最佳方法?

如何在 C 中编辑 struct 体中的多个变量