OS X上的GCC分配的内存超出预期

我正在使用Mac OS X 10.11.4和Xcode 7.3以及gcc编译器。 我用homebrew下载了valgrind 3.11。 当我用valgrind运行我的C程序时,这是输出

==4297== ==4297== HEAP SUMMARY: ==4297== in use at exit: 30,208 bytes in 188 blocks ==4297== total heap usage: 265 allocs, 77 frees, 40,286 bytes allocated ==4297== ==4297== LEAK SUMMARY: ==4297== definitely lost: 0 bytes in 0 blocks ==4297== indirectly lost: 0 bytes in 0 blocks ==4297== possibly lost: 2,064 bytes in 1 blocks ==4297== still reachable: 4,096 bytes in 1 blocks ==4297== suppressed: 24,048 bytes in 186 blocks ==4297== Rerun with --leak-check=full to see details of leaked memory ==4297== ==4297== For counts of detected and suppressed errors, rerun with: -v ==4297== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 

在整个程序中,我有2个mallocs和2个frees,所以我不知道为什么有265个allocs和更少的frees。 我问我的朋友谁使用ubuntu寻求帮助,当他用他的gcc编译我的代码并用valgrind运行程序时,它带回了3个allocs和3个释放,所以一切都是正确的。 我发现这可能发生在一些编译器库中,或者如果它们不是最新的,但我不知道如何在OS X中更新它们。

  • 这是我的代码

main.c中

 #include  #include  #include  #include  #include "game.h" int main(int argc, char** argv) { GAME team1; GAME team2; int len = 0; //only for valgrind if(argc == 2) { char* word; len = strlen(argv[1]) + 1; word = (char*)malloc(sizeof(char)*(len)); strcpy(word, argv[1]); team1.team_name = word; len = strlen("Team 2") + 1; word = (char*)malloc(sizeof(char)*(len)); strcpy(word, "Team 2"); team2.team_name = word; } else if(argc == 3) { char* word; len = strlen(argv[1]) + 1; word = (char*)malloc(sizeof(char)*(len)); strcpy(word, argv[1]); team1.team_name = word; len = strlen(argv[2]) + 1; word = (char*)malloc(sizeof(char)*(len)); strcpy(word, argv[2]); team2.team_name = word; } else { char* word; len = strlen("Team 1") + 1; word = (char*)malloc(sizeof(char)*(len)); strcpy(word, "Team 1"); team1.team_name = word; len = strlen("Team 2") + 1; word = (char*)malloc(sizeof(char)*(len)); strcpy(word, "Team 2"); team2.team_name = word; } int player1, player2, players_number; do { //PVP or PVAI printf("How many players will play this game? [1/2]: "); scanf("%d", &players_number); } while((players_number != 1) && (players_number != 2)); names(&team1, &team2); //add names abilities(&team1, &team2); //add hp, def, att render(&team1, &team2); //choosing first players printf("Choose player from Team 1: "); scanf("%d", &player1); while(getchar() != '\n') ; if(players_number == 2){ printf("Choose player from Team 2: "); scanf("%d", &player2); while(getchar() != '\n') ; } else { //If PVAI srand(time(NULL)); player2 = rand() % 5 + 1; printf("Choose player from Team 2: %d\n", player2); } ///////////////////////// do { //GAME if(team1.hp[player1 - 1] == 0) { printf("Choose player from Team 1: "); scanf("%d", &player1); while(getchar() != '\n') ; } if((team2.hp[player2 - 1] == 0) && (players_number == 2)) { printf("Choose player from Team 2: "); scanf("%d", &player2); while(getchar() != '\n') ; } else if(team2.hp[player2 - 1] == 0) { //If PVAI do { player2 = rand() % 5 + 1; } while(team2.hp[player2 - 1] == 0); printf("Choose players from Team 2: %d\n", player2); } printf("---------------------------\n"); battle(&team1, &team2, (player1 - 1), (player2 - 1)); render(&team1, &team2); } while(who_wins(&team1, &team2) == 0); printf("Team %d wins!\n", who_wins(&team1, &team2)); free(team1.team_name); free(team2.team_name); return 0; } 

game.c

 #include  #include  #include  #include  #include  //for delay #include  //for file size #include "game.h" void render(GAME *team1, GAME *team2) { //rendering the gaming table printf("%s\tHP\tDEF\tATT\n", team1->team_name); printf("---------------------------\n"); for(int i = 0; i name[i], team1->hp[i], team1->def[i], team1->att[i]); } printf("---------------------------\n"); printf("%s\n", team2->team_name); printf("---------------------------\n"); for(int i = 0; i name[i], team2->hp[i], team2->def[i], team2->att[i]); } printf("---------------------------\n"); } void names(GAME *team1, GAME *team2) { //choose random names from *.txt file printf("Generating teams...\n"); FILE *fr = fopen("NAMES.txt", "r"); if(fr == NULL) { printf("The file with names is not allowed, we will use pre-defined names for you.\n"); non_generated_names(&team1, &team2); return; //can use exit instead of return and exit the program if names are not allowed } struct stat st; stat("NAMES.txt", &st); int size = st.st_size; srand(time(NULL)); for(int i = 0; i name[i]) == EOF) i--; } for(int i = 0; i name[i]) == EOF) i--; } printf("Success!\n"); printf("---------------------------\n"); fclose(fr); } void non_generated_names(GAME **team1, GAME **team2) { //if *.txt file is not allowed, this is used for adding pre-defined names for(int i = 0; i name[i], "Jack"); break; case 1: strcpy((*team1)->name[i], "Jim"); break; case 2: strcpy((*team1)->name[i], "John"); break; case 3: strcpy((*team1)->name[i], "Tom"); break; case 4: strcpy((*team1)->name[i], "Hank"); break; } } for(int i = 0; i name[i], "Tim"); break; case 1: strcpy((*team2)->name[i], "Mark"); break; case 2: strcpy((*team2)->name[i], "Alf"); break; case 3: strcpy((*team2)->name[i], "Ted"); break; case 4: strcpy((*team2)->name[i], "Bil"); break; } } } void abilities(GAME *team1, GAME *team2) { //add HP, ATT and DEF to players srand(time(NULL)); for(int i = 0; i hp[i] = 5; team2->hp[i] = 5; team1->def[i] = rand() % 4 + 1; team1->att[i] = 5 - team1->def[i]; team2->def[i] = rand() % 4 + 1; team2->att[i] = 5 - team2->def[i]; } } int who_wins(GAME *team1, GAME *team2) { //tests if someone and who wins the game int win = 2; for(int i = 0; i hp[i] != 0) { win = 1; break; } } if(win == 2) return 2; for(int i = 0; i hp[i] != 0) { win = 0; break; } } if(win == 1) return 1; return 0; } void change_attacker(int *attacker) { //swap 1 and 2 if(*attacker == 1) *attacker = 2; else if(*attacker == 2) *attacker = 1; } void battle(GAME *team1, GAME *team2, int player1, int player2) { //Battle engine srand(time(NULL)); int attacker = rand() % 2 + 1; //random team to start printf("Battle begins in few seconds...\n"); //sleep(1); //disabled delays for testing if(attacker == 1) { printf("%s will starts...\n", team1->team_name); } else printf("%s will starts...\n", team2->team_name); //sleep(1); printf("\n!!!START!!!\n\n"); printf("---------------------------\n"); while((team1->hp[player1] != 0) && (team2->hp[player2] != 0)) { //sleep(1); //delay if(attacker == 1) { if((rand() % (team1->att[player1] + team2->def[player2]) + 1) > team2->def[player2]) { team2->hp[player2]--; printf("Attacker wins!\n"); if(team2->hp[player2] != 0) printf("%s from %s has been hit, %d HP remaining.\n", team2->name[player2], team2->team_name, team2->hp[player2]); else printf("%s from %s is dead!\n", team2->name[player2], team2->team_name); printf("---------------------------\n"); } else { printf("Defender wins!\n"); printf("---------------------------\n"); } } else if(attacker == 2) { if((rand() % (team1->def[player1] + team2->att[player2]) + 1) > team1->def[player1]) { team1->hp[player1]--; printf("Attacker wins!\n"); if(team1->hp[player1] != 0) printf("%s from %s has been hit, %d HP remaining.\n", team1->name[player1], team1->team_name, team1->hp[player1]); else printf("%s from %s is dead!\n", team1->name[player1], team1->team_name); printf("---------------------------\n"); } else { printf("Defender wins!\n"); printf("---------------------------\n"); } } change_attacker(&attacker); } } 

你在Mac OS X上看到的大多数都是“正常”的.C启动代码在调用main()之前会进行大量的内存分配,并且大部分都没有被释放。 抑制很重要。

创建这样的程序:

 int main(void) { return 0; } 

并在我的Mac OS X 10.11.4机器(GCC 6.1.0)上运行它产生:

 ==58367== Memcheck, a memory error detector ==58367== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==58367== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info ==58367== Command: ./xx ==58367== ==58367== ==58367== HEAP SUMMARY: ==58367== in use at exit: 22,233 bytes in 186 blocks ==58367== total heap usage: 270 allocs, 84 frees, 28,465 bytes allocated ==58367== ==58367== LEAK SUMMARY: ==58367== definitely lost: 0 bytes in 0 blocks ==58367== indirectly lost: 0 bytes in 0 blocks ==58367== possibly lost: 0 bytes in 0 blocks ==58367== still reachable: 0 bytes in 0 blocks ==58367== suppressed: 22,233 bytes in 186 blocks ==58367== ==58367== For counts of detected and suppressed errors, rerun with: -v ==58367== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 

我得到了与XCode的clang编译相似的结果。 -v选项很吵,但信息量很大。

所有内存分配都是常规的,而不是值得担心的事情。

valgrind的输出中,您可能会丢失一些内存并且仍然可以访问内存。 你应该进一步探索,找出它们是什么。 --leak-check=full选项会有所帮助。 你最终也可以使用--gen-suppressions选项( valgrind --help来探索可用的选项),然后在重新运行时使用--suppressions=your-suppressions-file

我有一个文件中有22个抑制,我有时需要使用它。 我曾经有更多的抑制,但valgrind自动做得更好。 保持valgrind当前通常也是一个好主意; Mac OS X升级后重建是一个好主意。


如果OS X自己分配内存,我如何检查我的程序?

leak13.c

 #include  #include  #include  int main(void) { char *s = malloc(33); strcpy(s, "Adjudication"); printf("[%s]\n", s); /* free(s); // leak! */ return 0; } 

与valgrind一起运行

 $ valgrind --leak-check=full leak13 ==2301== Memcheck, a memory error detector ==2301== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==2301== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info ==2301== Command: leak13 ==2301== [Adjudication] ==2301== ==2301== HEAP SUMMARY: ==2301== in use at exit: 26,362 bytes in 188 blocks ==2301== total heap usage: 272 allocs, 84 frees, 32,594 bytes allocated ==2301== ==2301== 33 bytes in 1 blocks are definitely lost in loss record 24 of 65 ==2301== at 0x100007CF1: malloc (vg_replace_malloc.c:302) ==2301== by 0x100000F4D: main (leak13.c:7) ==2301== ==2301== LEAK SUMMARY: ==2301== definitely lost: 33 bytes in 1 blocks ==2301== indirectly lost: 0 bytes in 0 blocks ==2301== possibly lost: 0 bytes in 0 blocks ==2301== still reachable: 0 bytes in 0 blocks ==2301== suppressed: 26,329 bytes in 187 blocks ==2301== ==2301== For counts of detected and suppressed errors, rerun with: -v ==2301== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 18 from 18) $ 

在这里,源代码中第7行的malloc()显然存在一个泄漏。 (这是在Mac OS X 10.11.5上运行的,自升级以来没有重建过valgrindgcc 。这次似乎并不重要。)

当您在Linux上运行程序时,您可以获得完全干净的健康状况。 例如,在Ubuntu 14.04 LTS上,使用上面的代码,除了free是未注释的,我得到了输出:

 $ valgrind ./noleak13 ==38142== Memcheck, a memory error detector ==38142== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==38142== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info ==38142== Command: ./noleak13 ==38142== [Adjudication] ==38142== ==38142== HEAP SUMMARY: ==38142== in use at exit: 0 bytes in 0 blocks ==38142== total heap usage: 1 allocs, 1 frees, 33 bytes allocated ==38142== ==38142== All heap blocks were freed -- no leaks are possible ==38142== ==38142== For counts of detected and suppressed errors, rerun with: -v ==38142== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) $ 

在Mac OS X上你不会看到’所有堆块都是空闲的 – 没有泄漏可能’的消息,但是你可以丢失0个字节,0个字节间接丢失,0个字节可能丢失,0个字节仍然可以访问 – 除了被抑制物品 – 尽可能好。