2

I am currently trying to figure out why my program is using tons of process memory according to Visual Studio 2019 Diagnostic Tools. My program is essentially a simulation of ants and how they forage for food using SFML for drawing. It is in the very early stages but I figure this is something I need to figure out before it gets worse. I currently can simulate 500 ants and see that the program uses around 22GB of memory at max and will settle at around 12GB after the ants have been created and the simulation loop is running. I will try my best to provide the most relevant code pieces but for reference the full code is listed here.

Ant Simulator Github

My code is structured as such. I have a Simulator class that handles the simulation loop, creates all the objects and draws them to a window. I have an Ant class that takes a texture reference and a reference to another class(RNG) I made for generating Random numbers. Here is the constructor for the Ant class. I don't know if I have too much going on in the constructor.

Ant::Ant(sf::Texture& t, RNG& rng1) :
    speed(350),
    sigmaU(0),
    sigmaV(0),
    u(0),
    v(0),
    dir(0),
    stepSize(20),
    distance(0),
    animLength(0.015),
    moving(false),
    atDestination(true),
    currentFrame{ rectangle, 0, FrameDirection::kForward },
    texture(t),
    rectangle(sf::IntRect(0, 0, 538, 759)),
    rng(rng1),
    beta(1.5f)
  {
    windowSize = sf::Vector2f(X_BOUND, Y_BOUND);
    position = sf::Vector2f(START_X, START_Y);//current position.
    previousPos = sf::Vector2f(START_X, START_Y);
    destination = sf::Vector2f(START_X, START_Y);
    velocity = sf::Vector2f(0, 0);//speed at which we are moving.
    direction = sf::Vector2f(0, 0);//direction we are moving in.
    //width 538 length 759
    double scale = rng.generateRandomDouble();
    setSpeed(150 + scale * 200);

    sprite.setScale(0.035f + scale * 0.03, 0.035f + scale * 0.03);
    sprite.setPosition(position);
    sprite.setTexture(t);
    sprite.setTextureRect(rectangle);

    sigmaU = gamma(1 + beta) * sin(M_PI * beta / 2) / (gamma((1 + beta) / 2) * (double)beta * powf(2, (beta - 1) / 2));
    sigmaU = powf(sigmaU, 1 / beta);
    sigmaV = 1;
    

}

The loop where I add ants to a vector is where the memory usage spike happens and when it is in the while loop is when the memory settles to 10-12GB I put breakpoints at the start of each loop and took a snapshot. See Diagnostic Tools 1 image at end of post. What is on that picture that I need help understanding on how to find the root of such large memory usage is the "Allocations(Diff)" and "Heap Size(Diff)". At the start of the for loop is the first snapshot. There isn't much that has been done aside from initialize some elements in the Simulator class and call run(), so there is 5,770(n/a) under allocations and 16,909.21KB(n/a) for heap size. After the for loop completes, 16 seconds have passed, and Allocations shows 12,297(+6,527). Heap Size shows 21,028.75KB(+4,119.54KB). When I click on either of those links it brings up a window that I am having trouble understanding. In Diagnostics Tools 1 image I clicked on (+6527) under Allocations. It shows various objects and sizes but the numbers and counts are not making sense to me. So my question becomes where should I be looking to track this leak down and how can I reduce my memory footprint?

I have tried to use this article as a guide but it has not really helped much.

void Simulator::run()
{
    sf::Event ev;

    if (!texture.loadFromFile("black-ant-walk.png"))
    {
        cout << "error loading sprite" << endl << endl;
    }
    sf::Texture& ref = texture;

    for (int i = 0; i < NUM_ANTS; i++)//breakpoint set here to capture first snapshot of everything since main() started.
    {
        ants.push_back(Ant(ref, rng));//this process takes 24 GB of process memory at 1000 ants. need to reduce.
        //ants is declared as vector<Ant> ants; in a separate header file.
    }

    while (window.isOpen())//second breakpoint here and second snapshot taken here.
    {
        while (window.pollEvent(ev))
        {
            if (ev.type == sf::Event::Closed) window.close();

            if (ev.type == sf::Event::Resized) onResize(ev);

            handleMouse(ev);
        }
        simLoop();//33ms at 700 ants. eventually settles to 46ms at 1000 ants. 
        draw();
    }
}

Diagnostic Tools 1

Diagnostic Tools 2 image is showing the snapshot each time the vector has to increase in size up to around ~200 ants so it did not finish the loop in this image.

Diagnostic Tools 2

jpena51
  • 21
  • 2
  • 1
    To figure out if it is memory leaking, you should create a local vector in form of the loop to which you push your ants and then check if all memory is freed after that vector is destroyed. If that's the case then you can rule out memory leaking. Based on the code - without running it - it does not look like there is leaking taking place in the loop. To figure out what tasks such a huge amount of memory, you could comment about parts of your members until you figure out which member(s) of Ant are responsible for that. – t.niese Sep 11 '20 at 09:57
  • 1
    A side note normally you don't want to have an own random number generator for each ant, but a shared one `std::mt19937_64` uses a relatively high amount of memory per instance (about 2KB) this is for sure not the reason for those GB of used memory, but something to keep in mind. – t.niese Sep 11 '20 at 10:00
  • 1
    I would guess that the high memory usage is coming from the ```Ant``` members ```sf::Sprite``` and ```sf::Texture```. The individual ants should maybe not have their own instance but only the reference or ```shared_ptr``` to the ```sf::Texture```. It seems like every ant has the Same texture. – Thrasher Sep 11 '20 at 10:53
  • 1
    Also take a look at [range-based for-loop](https://en.cppreference.com/w/cpp/language/range-for). No need for explicit iterators over ```vector```. And don't store this ```iter``` as class member. Better have it locally in your loop if using it. – Thrasher Sep 11 '20 at 10:57
  • So this is where my understanding of references and pointers really does not shine. I thought I was passing a reference to each ant rather than a copy of each texture because previously the textures were not rendering until I would pass the reference through the constructor. Same for the RNG class which I assumed would only have 1 random number generator shared for all ants. I see in my `Ant` class I had remnants when I was storing a texture for each ant. I removed it from my code and even commented out the sprite.set() commands and it still seems to be using lots of memory. – jpena51 Sep 11 '20 at 19:32
  • @t.niese @Thrasher Ok so what it was is really simple because of all the iterations I've gone through I still had this in the variable initialization list for `Ant` `texture(t)` even though I was not using `sf::Texture texture` anymore. deleting that got rid of GB of memory usage and now I am at a cool 95MB for 1000 ants. Thank you all but I would still like to know how I could have used visual studio to find that out. – jpena51 Sep 11 '20 at 19:40
  • 1
    @jpena51 Yes, you're passing texture by refernence but than you save an texture object in each Ant. So the object that you refernced gets copied to the Ant. You have to store the reference or pointer to a texture if you dont want that. Be aware that you than need something that manages the lifetime of your textures eg a ```std::share_ptr``` – Thrasher Sep 15 '20 at 12:14
  • 1
    @jpena51 With debugging your memory footprint I can't help you. Sry – Thrasher Sep 15 '20 at 12:15

0 Answers0