2012-04-14 19 views
10

Jestem profilowania kodu gry, którą napisałem i zastanawiam się, jak to możliwe, że poniższy fragment powoduje wzrost sterty o 4kb (profiluję z Heapshot Analysis Xcode) za każdym razem, gdy jest wykonywany:Wycie spowodowane przez strach

u8 WorldManager::versionOfMap(FILE *file) 
{ 
    char magic[4]; 
    u8 version; 

    fread(magic, 4, 1, file); <-- this is the line 
    fread(&version,1,1,file); 
    fseek(file, 0, SEEK_SET); 

    return version; 
} 

Według profilera podświetlona linia przydziela 4.00Kb pamięci z malloc każdym razem, gdy funkcja jest wywoływana, pamięci, która nigdy nie zostanie zwolniony. To zdaje się zdarzyć z innymi połączeniami do kodu fread, ale to było najbardziej wyzywające.

Czy brakuje mi czegoś trywialnego? Czy to jest coś wewnętrznego, o co nie powinienem się martwić?

Tak jak w notatce: Profiluję ją na iPhonie i jest skompilowana jako wersja (-O2).

+4

co się dzieje, gdy zmienisz go na 'fread (magic, 1, 4, file);'? – Yahia

+0

Czy sprawdziłeś błędy odczytu (np. Z 'ferror (plik)')? – Beta

+0

inny punkt: sprawdź wynik wywołania 'fread'! – Yahia

Odpowiedz

3

Jeśli to, co opisujesz, dzieje się naprawdę, a twój kod nie zawiera błędów w innych miejscach, to jest to błąd w implementacji, jak sądzę.

Prawdopodobnie uważam, że nie można zamknąć pliku. Strumienie Stdio domyślnie korzystają z buforowania, jeśli urządzenie nie jest interaktywne, a bufor jest przydzielany w momencie otwarcia pliku lub wykonania operacji we/wy. Chociaż należy przydzielić tylko jeden bufor, można z pewnością przeciekać bufor, zapominając o zamknięciu pliku. Ale na pewno zamknięcie pliku powinno zwolnić bufor. Nie zapomnij sprawdzić wartości zwróconej przez fclose.

Przypuśćmy, że poprawnie zamkniesz plik, ale w twoim kodzie jest kilka innych gitar, które nie będą powodowały tego problemu, ale wspomnę o tym.

Najpierw wywołanie fread odczytuje obiekt mający jednego członka o rozmiarze 4. W rzeczywistości obiekt ma 4 elementy wielkości 1. Innymi słowy, argumenty numeryczne do fread są zamieniane. To czyni różnicę tylko w znaczeniu wartości zwracanej (ważne w przypadku częściowego odczytu).

Po drugie, podczas gdy pierwsze połączenie do fread poprawnie twarde kody wielkość char jako 1 (w C, który jest definicja „wielkości”), to chyba lepiej stylistycznie używać sizeof(u8) w drugim naborze do fread.

Jeśli pomysł, że to naprawdę jest przeciek pamięci jest prawidłową interpretacją (i nie ma żadnych błędów w innym miejscu), być może uda ci się obejść problem, wyłączając buforowanie stdio dla tego konkretnego pliku:

bool WorldManager::versionOfMap(FILE *file, bool *is_first_file_io, u8 *version) 
{ 
    char magic[4]; 
    bool ok = false; 
    if (*is_first_file_io) 
    { 
    // we ignore failure of this call 
    setvbuf(file, NULL, _IONBF, 0); 
    *is_first_file_io = false; 
    } 

    if (sizeof(magic) == fread(magic, 1, sizeof(magic), file) 
     && 1 == fread(version, sizeof(*version), 1, file)) 
    { 
     ok = true; 
    } 
    if (-1 == fseek(file, 0L, SEEK_SET)) 
    { 
     return false; 
    } 
    else 
    { 
     return ok && 0 == memcmp(magic, EXPECTED_MAGIC, sizeof(magic)); 
    } 
} 

Nawet jeśli idziemy z hipotezą, że to naprawdę jest błąd, a przeciek jest prawdziwy, warto skondensować swój kod do najmniejszego możliwego przykładu, który nadal pokazuje problem. Jeśli to ujawni prawdziwy błąd, wygrasz. W przeciwnym razie będziesz potrzebował minimalnego przykładu, aby zgłosić błąd w implementacji.

Powiązane problemy