我的目标是优化内存使用...我从未在任何教程中看到过它让我认为这不是正确的方法
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Player {
char* username;
int hp;
int mp;
};
int main(void) {
struct Player test, *p = &test;
p->username = (char*)malloc(50 * sizeof(char));
scanf("%s", p->username);
p->username = realloc(p->username, (strlen(p->username) + 1) * sizeof(char));
printf("%s", p->username);
return 0;
}
正确的方法来优化内存使用?
暂时重复使用的缓冲区通常可以是慷慨的并且大小固定。
分配适当大小的内存量对于成员.username
来说代码可能适用于数百万的struct Player
。
IOWs,使用分配代码的可变大小方面。如果struct Player
是2人棋,char username[50]
大小是有道理的。对于多玩家宇宙,char *
是有道理的。
而不是两次调用*alloc()
考虑一个正确大小的呼叫。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// Reasonable upper bound
#define USERNAME_SIZEMAX 50
struct Player {
char* username;
int hp;
int mp;
};
int main(void) {
puts("Enter user name");
// Recommend 2x - useful for leading/trailing spaces & detecting excessive long inputs.
char buf[USERNAME_SIZEMAX * 50];
if (fgets(buf, sizeof buf, stdin) == NULL) {
puts("No input");
} else {
trim(buf); // TBD code to lop off leading/trailing spaces
if (!valid_name(buf)) { // TBD code to validate the `name`
printf("Bad input \"%s\"\n", buf);
} else {
struct Player test = { 0 }; // fully populate
test.username = malloc(strlen(buf) + 1);
// Maybe add NULL check here
strcpy(test.username, buf);
// Oh happy day!
printf("%s", p->username);
return EXIT_SUCCESS;
}
}
return EXIT_FAILURE;
}
一些技巧:
a)示例代码太小而无关紧要
b)永远不要使用malloc()
作为你总是想要的东西。相反,预分配(例如,作为全局变量)或(如果它足够小)使用局部变量来避免malloc()
的开销。例如。:
int main(void) {
struct Player test, *p = &test;
char userName[50];
p->username = userName;
c)不要在整个地方传播数据。您希望所有数据位于同一位置(在最少数量的缓存行中,同时使用的数据尽可能彼此接近)。一种方法是组合多个项目。例如。:
struct Player {
char username[50];
int hp;
int mp;
};
int main(void) {
struct Player test, *p = &test;
d)如果某些东西(最多)有50个字符的内存;不要费心使用realloc()
浪费CPU时间并可能浪费更多内存。不要忘记malloc()
和realloc()
的内部代码会将元数据添加到每个分配的内存块中,这可能会花费额外的16个字节或更多。
一般来说;为了表现,应该完全避免malloc()
和realloc()
(以及new()
和......)(特别是对于大型节目)。他们在任何地方“随机”传播数据并破坏了获得良好局部性的任何希望(这对于最小化多个非常昂贵的东西很重要 - 缓存未命中,TLB未命中,页面错误,交换空间使用......)。
注意:scanf()
和gets()
也应该被禁止。它们无法防止缓冲区溢出(例如,当只有足够的内存分配给50个字符时,用户提供超过50个字符,故意捣毁/破坏其他数据),这会导致巨大的安全漏洞。