Olio-ohjelmointi
Muistivuotojen tutkiminen Heob-työkalulla

Voit ladata ja asentaa Heob-sovelluksen sivulta https://github.com/ssbssa/heob. Kun olet purkanut tuon johonkin kansioon, lisää tuon kansion polku Qt Creatorissa "Analyze->Heob". Voit ladata ja kopioida samaan kansioon dll tiedostot sivulta https://github.com/ssbssa/dwarfstack

Heob (Heap Observer) on Qt Creatoriin integroitu työkalu, joka auttaa havaitsemaan muistivuotoja Windows-ympäristössä. Tässä harjoituksessa opetellaan tunnistamaan ja korjaamaan muistivuotoja C++-ohjelmissa.

Miksi Heob eikä Valgrind?

Qt Creatorin Analyze-valikossa näkyy myös Valgrind-työkalu, joka on alan standardi muistivuotojen havaitsemiseen. Valgrind ei kuitenkaan toimi Windowsissa - se on käytettävissä vain Linux-järjestelmissä. Heob on kehitetty juuri Windowsia varten ja tarjoaa vastaavan toiminnallisuuden kuin Valgrind Linuxissa.

Muistivuoto - mitä se on?

Muistivuoto tapahtuu, kun ohjelma varaa muistia dynaamisesti (esim. new-komennolla), mutta ei vapauta sitä (delete-komento puuttuu). Tämä johtaa siihen, että ohjelma kuluttaa yhä enemmän muistia, mikä voi lopulta kaataa koko järjestelmän.

Yleisiä muistivuotojen syitä:

  • Raakaosoitin (new) ilman vastaavaa delete-komentoa
  • Poikkeukset, jotka estävät delete-komennon suorittamisen
  • Monimutkainen omistajuuslogiikka osoittimissa
  • Syklinen viittaus älykkäillä osoittimilla (shared_ptr)
Heobin käyttö Qt Creatorissa

Vaihe 1: Käynnistä Heob

  1. Avaa projektisi Qt Creatorissa
  2. Valitse valikosta Analyze → Heob
  3. Varmista, että projektisi on käännetty Debug-tilassa

Vaihe 2: Aja ohjelma Heobin valvonnassa

  1. Kun valitset Heob-työkalun, ohjelma käynnistyy automaattisesti
  2. Suorita ohjelma normaalisti loppuun asti
  3. Kun ohjelma päättyy, Heob luo raportin muistivuodoista (build/leaks.xml)

Vaihe 3: Analysoi raportti

Heob näyttää tarkat tiedot muistivuodoista:

  • Montako tavua muistia on vuotanut
  • Missä kohtaa koodia muisti varattiin (new)
  • Rivinumerot, joista vuoto alkoi
Heobin asetukset Qt Creatorissa

Sivulla https://doc.qt.io/qtcreator/creator-heob.html kerrotaan Heobin asetuksista. Extra arguments-kohtaan kannatta laittaa seuraavaa

-oleaks.html -g2 -L1024
Edellisen ansiosta tulokset saadaan html-muodossa.

Esimerkki: Muistivuoto silmukassa

Tämä on hyvä esimerkki muistivuodoista, koska ongelma on helppo havaita ja korjata. Luo Qt Creator -projekti ja jaa koodi seuraaviin tiedostoihin:

dog.h

#ifndef DOG_H
#define DOG_H

#include <string>
using namespace std;

class Dog {
private:
    string name;
public:
    Dog(string n);
    ~Dog();
    void bark();
};

#endif // DOG_H

dog.cpp

#include "dog.h"
#include <iostream>
using namespace std;

Dog::Dog(string n) : name(n) {
    cout << "Koira " << name << " luotiin" << endl;
}

Dog::~Dog() {
    cout << "Koira " << name << " tuhotaan" << endl;
}

void Dog::bark() {
    cout << name << " haukkuu!" << endl;
}

main.cpp (SISÄLTÄÄ MUISTIVUODON)

#include "dog.h"

int main() {
    for (int i = 0; i < 5; i++) {
        Dog* dog = new Dog("Koira" + to_string(i));
        dog->bark();
        // VIRHE: delete puuttuu!
        // Jokaisella kierroksella vuotaa muistia
    }
    return 0;
}

Ongelma: Silmukka luo 5 Dog-oliota, mutta yhtäkään ei tuhota. Konsoliin tulostuu vain "luotiin"-viestit, mutta ei yhtään "tuhotaan"-viestiä!

Minulla Heob tuotti seuraan tuloksen tulos1

Korjaus (tapa 1): Lisää delete

Korjaus (tapa 2): Käytä unique_ptr (SUOSITELTU)

#include "dog.h"
#include <memory>

int main() {
    for (int i = 0; i < 5; i++) {
        auto dog = std::make_unique<Dog>("Koira" + to_string(i));
        dog->bark();
        // Muisti vapautuu automaattisesti jokaisen kierroksen lopussa
    }
    return 0;
}

Korjauksen jälkeen Heob tuotti seuraan tuloksen tulos2

Heobin tulos:

  • Heob luo leaks.xml-tiedoston projektin ja myös html-tiedoston, jos käytät em. asetuksia build-kansioon
  • Avaa XML-tiedosto selaimessa luettavaksi
  • Korjaamattomassa koodissa näkyy useita <error>-tageja
  • Korjatussa koodissa ei ole <error>-tageja lainkaan

Huom! Heob saattaa raportoida pieniä (esim. 16 tavun) vuotoja, jotka tulevat MinGW:n C++ standardikirjastosta. Nämä ovat vääriä hälytyksiä (false positives) ja voidaan ignoorata. Keskity isoihin vuotoihin ja varsinkin siihen, että "tuhotaan"-viestit tulostuvat konsoliin!

Yhteenveto

Muistivuotojen välttäminen - parhaat käytännöt

Huono käytäntö ❌ Hyvä käytäntö ✅
Animal* a = new Dog(); auto a = make_unique<Dog>();
Animal* arr[] = {new Dog(), new Cat()}; vector<unique_ptr<Animal>> arr;
Manuaalinen delete Automaattinen muistinhallinta
Riski muistivuodoille Ei muistivuotoja

Muista: Modernissa C++:ssa (C++11 ja uudemmat) raakaosoittimien käyttö on harvoin tarpeen. Käytä aina älykkäitä osoittimia (unique_ptr, shared_ptr), kun tarvitset dynaamista muistinhallintaa!



Toggle Menu