pebal / sgcl

Smart Garbage Collection Library for C++
zlib License
163 stars 8 forks source link

fix bug: enable the program to collect all ptrs after terminated. #6

Closed bowen-xu closed 6 months ago

bowen-xu commented 8 months ago

Hi @pebal, I found this repo very fantastic and try to use it for GC in C++.

It seems that after the main function exits, some tracked instances are not destroyed properly, because their deconstruction functions are not executed, though there are no memory leaks. I guess this is because when calling terminate_collector(), the instances are still reachable. Although I'm not familar with GC and how it workds, I tried to make the program remove all objects by setting the marks as 0, and then call _remove_garbage()again.

Did I do it correctly? Please let me know if further modificaton is needed.

The code below is what I used for test.

#define SGCL_LOG_PRINT_LEVEL 2
#include "sgcl/sgcl.h"
#include <iostream>
#include <unistd.h>

using namespace std;
using namespace sgcl;

int n_objs = 0;

struct node
{
    float data;
    tracked_ptr<node> next;

    node()
    {
        n_objs++;
        std::cout << "\033[31mConstructor called " << this << "\033[0m" << std::endl;
    }

    ~node()
    {
        n_objs--;
        std::cout << "\033[32mDestructor called " << this << "\033[0m" << std::endl;
    }
};

auto tracked_node = make_tracked<node>();

auto foo(tracked_ptr<node> _node)
{
    // create nodes on tracked heap
    auto a = _node;
    for (int i = 0; i < 3; i++)
    {
        a->next = make_tracked<node>();
        a = a->next;
    }

    a->next = _node;
    std::cout << &_node << std::endl;
    _node.get();
    return _node;
}

void __main__()
{
    auto _tracked_node = tracked_node;
    auto tracked_num = make_tracked<node>();
    auto node = foo(_tracked_node);
    std::cout << &node << std::endl;

}

int main()
{
    __main__();
    terminate_collector();
}

Without _remove_all(), unexpectedly, some objects' deconstruction functions are not called.

image

With the added code in this pr, the program's behavior becomes correct:

image
pebal commented 8 months ago

Hello,

A have a little note to your test code. You can write auto _tracked_node = tracked_node instead auto _tracked_node = tracked_ptr<node>(tracked_node.get()) and _node.get() is unnecessary.

Regarding deleting objects. The objects are available from the global pointer tracked_node so they are not deleted. You can reset this pointer before the main function ends.

bowen-xu commented 8 months ago

A have a little note to your test code. You can write auto _tracked_node = tracked_node instead auto _tracked_node = tracked_ptr(tracked_node.get()) and _node.get() is unnecessary.

Got it.

Regarding deleting objects. The objects are available from the global pointer tracked_node so they are not deleted. You can reset this pointer before the main function ends.

Yes, I also found that. However, in some complex projects, we do not always remember which objects are global and needed to be reset manually. So I believe it woud be much better to make the program automatically delete all remaining objects when the gc is terminated.

bowen-xu commented 8 months ago

@pebal Is there anything for me to further modify?