GCC on OS X allocs more memory than expected

风格不统一 提交于 2019-12-13 01:28:47

问题


I am using Mac OS X 10.11.4 with Xcode 7.3 with gcc compiler in it. I downloaded valgrind 3.11 using homebrew. When I run my C program with valgrind, this is the output

==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)

In the whole program, I have 2 mallocs and 2 frees, so I have no idea why there are 265 allocs and fewer frees. I asked my friend who uses ubuntu for a help, and when he compiles my code with his gcc and run the program with valgrind, it brought back 3 allocs and 3 frees, so everything was correct. I found that this could happen in some compiler libraries, or if they are not up-to-date, but I have no idea how to update them in OS X.

  • Here is my code

main.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h> //for delay
#include <sys/stat.h> //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 <= 4; i++) {
        printf("%s\t%d\t%d\t%d\n", team1->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 <= 4; i++) {
        printf("%s\t%d\t%d\t%d\n", team2->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 <= 4; i++) {
        fseek(fr, ((rand() % size) + 1), SEEK_SET);
        if(fscanf(fr, "%*s\n%20s", team1->name[i]) == EOF)
            i--;
    }

    for(int i = 0; i <= 4; i++) {
        fseek(fr, ((rand() % size) + 1), SEEK_SET);
        if(fscanf(fr, "%*s\n%20s", team2->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 <= 4; i++) {
        switch(i) {
            case 0:
                strcpy((*team1)->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 <= 4; i++) {
        switch(i) {
            case 0:
                strcpy((*team2)->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 <= 4; i++) {

        team1->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 <= 4; i++) {
        if(team1->hp[i] != 0) {
            win = 1;
            break;
        }
    }

    if(win == 2)
        return 2;

    for(int i = 0; i <= 4; i++) {
        if(team2->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);
    }
}

回答1:


Most of what you're seeing is 'normal' on Mac OS X. The C startup code does a lot of memory allocation before calling main(), and most of it is not freed. The suppressions are important.

Creating a program like this:

int main(void)
{
    return 0;
}

and running it on my Mac OS X 10.11.4 machine (GCC 6.1.0) yields:

==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)

I get similar results compiling with clang from XCode. The -v option is noisy but informative.

All that memory allocation is routine, and not something it is worth worrying about.

In your output from valgrind, you have some possibly lost and some still reachable memory. You should explore further to find out what those are. The --leak-check=full option will help. You may end up using --gen-suppressions option too (valgrind --help to explore the options available), and then --suppressions=your-suppressions-file when rerunning.

I have a file with 22 suppressions in it that I sometimes need to use. I used to have a lot more suppressions, but valgrind has got better at doing them automatically. Keeping valgrind current is generally a good idea too; rebuilding after a Mac OS X upgrade is a good idea.


How I can check my program if OS X allocs memory by itself?

leak13.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

Running with 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)
$

Here, there's clearly one leak, from the malloc() at line 7 in the source code. (And this was run on Mac OS X 10.11.5 without having rebuilt valgrind or gcc since the upgrade. It doesn't seem to have mattered this time around.)

When you run a program on Linux, you can get a completely clean bill of health. For example, on Ubuntu 14.04 LTS, with the code as above except the free is uncommented out, I got the output:

$ 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)
$

You won't see the 'All heap blocks were free — no leaks are possible' message on Mac OS X, but you can 0 bytes lost, 0 bytes indirectly lost, 0 bytes possibly lost and 0 bytes still reachable — apart from the suppressed items — which is as good as it gets.



来源:https://stackoverflow.com/questions/37242021/gcc-on-os-x-allocs-more-memory-than-expected

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!