Przeglądaj źródła

refactor & feat: gc机制

SongZihuan 3 lat temu
rodzic
commit
2cb2c3b7af

+ 9 - 14
include/core/gc.h

@@ -18,34 +18,29 @@ namespace aFuncore {
         inline void delReference();
         [[nodiscard]] inline GcCount getReference() const;
         inline void setClear(bool clear=false);
-        inline void setReachable(bool is_reference=false);
 
+        static void checkReachable(std::list<GcObjectBase *> &list);
+        static void setReachable(std::list<GcObjectBase *> &list, std::queue<GcObjectBase *> &des, std::queue<GcObjectBase *> &del);
+        static void destructUnreachable(std::queue<GcObjectBase *> &des, Inter &gc_inter);
+        static void deleteUnreachable(std::queue<GcObjectBase *> &del);
         static void destructAll(std::list<GcObjectBase *> &list, Inter &gc_inter);
+        static void deleteAll(std::list<GcObjectBase *> &list);
     protected:
         std::mutex lock;
 
         inline GcObjectBase();
         virtual ~GcObjectBase() = default;
 
+        virtual void destruct(Inter &gc_inter);
+        virtual void linkObject(std::queue<GcObjectBase *> &queue);
+
     private:
+        bool done_destruct;
         bool not_clear;  // 不清除
         bool reachable;  // 可达标记 [同时标识已迭代]
         GcCount reference;  // 引用计数
     };
 
-
-    class AFUN_CORE_EXPORT GcList {
-    public :
-        size_t add(GcObjectBase *obj);
-        GcObjectBase *pop();
-
-        [[nodiscard]] inline size_t getSize() const;
-        [[nodiscard]] inline size_t isEmpty() const;
-
-    private:
-        std::queue<GcObjectBase *> queue;
-    };
-
 };
 
 #include "gc.inline.h"

+ 1 - 14
include/core/gc.inline.h

@@ -3,7 +3,7 @@
 #include "gc.h"
 
 namespace aFuncore {
-    inline GcObjectBase::GcObjectBase() : not_clear{false}, reference{1}, reachable{false} {
+    inline GcObjectBase::GcObjectBase() : not_clear{false}, reference{1}, reachable{false}, done_destruct{false} {
 
     }
 
@@ -24,19 +24,6 @@ namespace aFuncore {
     inline void GcObjectBase::setClear(bool clear) {
         not_clear=!clear;
     }
-
-    inline void GcObjectBase::setReachable(bool is_reference) {
-        reachable=is_reference;
-    }
-
-
-    inline size_t GcList::getSize() const {
-        return queue.size();
-    }
-
-    inline size_t GcList::isEmpty() const {
-        return queue.empty();
-    }
 }
 
 #endif //AFUN_GC_INLINE_H

+ 3 - 0
include/core/inter.h

@@ -42,11 +42,14 @@ namespace aFuncore {
         bool destruct;
         std::list<GcObjectBase *> gc;
         Inter &gc_inter;  /* 需要在lock和reference后初始化 */
+        std::thread gc_thread;
 
         ProtectVarSpace *const protect;  // 保护变量空间
         VarSpace *const global;  // 全局变量空间
         VarList *const global_varlist;  // global + protect
         EnvVarSpace envvar;
+
+        void gcThread();
     };
 
     class AFUN_CORE_EXPORT Inter {

+ 4 - 0
include/core/var.h

@@ -21,6 +21,7 @@ namespace aFuncore {
 
         [[nodiscard]] inline virtual Object *getData();
         virtual void inline setData(Object *data_);
+        void linkObject(std::queue<GcObjectBase *> &queue) override;
 
     private:
         Object *data;
@@ -55,6 +56,7 @@ namespace aFuncore {
         virtual VarOperationFlat delVar(const std::string &name);
 
         [[nodiscard]] Object *findObject(const std::string &name);
+        void linkObject(std::queue<GcObjectBase *> &queue) override;
 
         static const size_t VAR_HASH_SIZE = 100;  // 环境变量哈希表大小
 
@@ -104,6 +106,8 @@ namespace aFuncore {
         virtual bool delVar(const std::string &name);
         [[nodiscard]] inline Object *findObject(const std::string &name);
 
+        inline void GcLinkObject(std::queue<GcObjectBase *> &queue);  /* 虽然不是GcObject, 但是也设定改函数便于将其包含的varspace快速压入queue中 */
+
     protected:
         std::mutex lock;
 

+ 5 - 0
include/core/var.inline.h

@@ -52,6 +52,11 @@ namespace aFuncore {
         Var *var = findVar(name);
         return var ? var->getData() : nullptr;
     }
+
+    inline void VarList::GcLinkObject(std::queue<GcObjectBase *> &queue) {
+        for (auto var : varspace)
+            queue.push(var);
+    }
 }
 
 #endif //AFUN_VAR_INLINE_H

+ 1 - 1
include/tool/tool-regex.h

@@ -7,7 +7,7 @@ namespace aFuntool {
         std::regex re;  // 正则表达式
         std::string pattern;  // 正则表达式的字符串
     public:
-        inline explicit Regex(std::string pattern_) noexcept(false);
+        inline explicit Regex(const std::string &pattern_) noexcept(false);
         inline Regex(const Regex &regex) noexcept;
         inline Regex(Regex &&regex) noexcept;
         Regex &operator=(const Regex &regex)=delete;

+ 1 - 1
include/tool/tool-regex.inline.h

@@ -4,7 +4,7 @@
 #include "tool-regex.h"
 
 namespace aFuntool {
-    inline Regex::Regex(std::string pattern_) noexcept(false) : re{pattern_}, pattern{std::move(pattern_)} {
+    inline Regex::Regex(const std::string &pattern_) noexcept(false) : re{pattern_}, pattern{pattern_} {
         if (!isCharUTF8(pattern))
             throw RegexException("Pattern not utf-8");
     }

+ 63 - 12
src/core/gc.cpp

@@ -1,25 +1,76 @@
 #include "gc.h"
 #include "inter.h"
+#include "init.h"
 
 namespace aFuncore {
     void GcObjectBase::destructAll(std::list<GcObjectBase *>& list, Inter &gc_inter) {
-        for (auto obj : list) {
-            delete obj;
+        for (auto obj : list)
+            if (!obj->done_destruct) {
+                obj->done_destruct = true;
+                obj->destruct(gc_inter);
+            }
+    }
+
+    void GcObjectBase::deleteAll(std::list<GcObjectBase *>& list) {
+        while (!list.empty())
+            delete list.front();  /* 自带pop */
+        if (!list.empty())
+            warningLog(aFunCoreLogger, "After GcObjectBase destructAll, list is not empty");
+    }
+
+    void GcObjectBase::destruct(Inter &inter) {
+        /* 什么都不做, 但virtual函数不能是inline */
+    }
+
+    void GcObjectBase::linkObject(std::queue<GcObjectBase *> &queue) {
+        /* 什么都不做, 但virtual函数不能是inline */
+    }
+
+    void GcObjectBase::checkReachable(std::list<GcObjectBase *> &list) {
+        std::queue<GcObjectBase *> queue;
+
+        for (auto *obj : list) {
+            obj->reachable = false;
+            if (obj->reference > 0 || obj->not_clear)
+                queue.push(obj);
+        }
+
+        while (!queue.empty()) {
+            auto obj = queue.front();
+            if (!obj->reachable) {
+                obj->reachable = true;
+                obj->linkObject(queue);
+            }
+            queue.pop();
         }
-        list.clear();
     }
 
-    size_t GcList::add(GcObjectBase *obj){
-        queue.push(obj);
-        return queue.size();
+    void GcObjectBase::setReachable(std::list<GcObjectBase *> &list, std::queue<GcObjectBase *> &des,
+                                    std::queue<GcObjectBase *> &del) {
+        for (auto *obj : list) {
+            if (!obj->reachable) {
+                if (obj->done_destruct)
+                    del.push(obj);
+                else
+                    des.push(obj);
+            }
+        }
     }
 
-    GcObjectBase *GcList::pop(){
-        if (queue.empty())
-            return nullptr;
+    void GcObjectBase::destructUnreachable(std::queue<GcObjectBase *> &des, Inter &gc_inter) {
+        while (!des.empty()) {
+            auto obj = des.front();
+            obj->done_destruct = true;
+            obj->destruct(gc_inter);
+            des.pop();
+        }
+    }
 
-        GcObjectBase *ret = queue.front();
-        queue.pop();
-        return ret;
+    void GcObjectBase::deleteUnreachable(std::queue<GcObjectBase *> &del) {
+        while (!del.empty()) {
+            auto obj = del.front();
+            del.pop();
+            delete obj;
+        }
     }
 }

+ 29 - 7
src/core/inter.cpp

@@ -171,6 +171,25 @@ namespace aFuncore {
         return true;
     }
 
+    void Environment::gcThread() {
+        while(true) {
+            std::queue<GcObjectBase *> del;
+            std::queue<GcObjectBase *> des;
+            {
+                std::unique_lock<std::mutex> mutex{lock};
+                if (destruct)
+                    break;
+                GcObjectBase::checkReachable(gc);
+                GcObjectBase::setReachable(gc, des, del);
+            }
+            GcObjectBase::deleteUnreachable(del);
+            GcObjectBase::destructUnreachable(des, gc_inter);
+            aFuntool::safeSleep(1);
+        }
+
+        GcObjectBase::destructAll(gc, gc_inter); /* 不需要mutex锁 */
+    }
+
     Environment::Environment(int argc, char **argv)
         : reference{0}, gc_inter{*(new Inter(*this))},
           protect{new ProtectVarSpace(*this)}, global{new VarSpace(*this)},
@@ -189,6 +208,8 @@ namespace aFuncore {
             snprintf(buf, 10, "sys:arg%d", i);
             envvar.setString(buf, argv[i]);
         }
+
+        gc_thread = std::thread([this](){this->gcThread();});
     }
 
     Environment::~Environment() noexcept(false) {
@@ -200,17 +221,18 @@ namespace aFuncore {
             if (destruct)
                 return;
 
-            delete global_varlist;
-
-            protect->delReference();
-            global->delReference();
-
             destruct = true;
         }
 
-        GcObjectBase::destructAll(gc, gc_inter);
-
+        gc_thread.join();
         delete &gc_inter;
+
+        delete global_varlist;
+        protect->delReference();
+        global->delReference();
+
+        GcObjectBase::deleteAll(gc); /* 不需要mutex锁 */
+
         if (reference != 0)
             throw EnvironmentDestructException();
     }

+ 4 - 2
src/core/value.cpp

@@ -6,17 +6,19 @@ namespace aFuncore {
     Object::Object(std::string type_, Inter &inter)
             : type{std::move(type_)}, env{inter.getEnvironment()}{
         std::unique_lock<std::mutex> mutex{env.lock};
-        env.gc.push_front(this);
+        env.gc.push_back(this);
     }
 
     Object::Object(std::string type_, Environment &env_)
             : type{std::move(type_)}, env{env_}{
         std::unique_lock<std::mutex> mutex{env.lock};
-        env.gc.push_front(this);
+        env.gc.push_back(this);
     }
 
     Object::~Object() {
         if (getReference() != 0)
             warningLog(aFunCoreLogger, "Object %p destruct reference: %d", this, getReference());
+        std::unique_lock<std::mutex> mutex{env.lock};
+        env.gc.remove(this);
     }
 }

+ 19 - 5
src/core/var.cpp

@@ -1,38 +1,47 @@
 #include "var.h"
+#include "value.h"
 #include "inter.h"
 #include "init.h"
 
 namespace aFuncore {
     Var::Var(Object *data_, Inter &inter) : data{data_}, env{inter.getEnvironment()}{
         std::unique_lock<std::mutex> mutex{env.lock};
-        env.gc.push_front(this);
+        env.gc.push_back(this);
     }
     
     Var::Var(Object *data_, Environment &env_) : data{data_}, env{env_}{
         std::unique_lock<std::mutex> mutex{env.lock};
-        env.gc.push_front(this);
+        env.gc.push_back(this);
     }
 
     Var::~Var() {
         if (getReference() != 0)
             warningLog(aFunCoreLogger, "Var %p destruct reference: %d", this, getReference());
+        std::unique_lock<std::mutex> mutex{env.lock};
+        env.gc.remove(this);
     }
     
     VarSpace::VarSpace(Inter &inter) : env{inter.getEnvironment()}{
         std::unique_lock<std::mutex> mutex{env.lock};
-        env.gc.push_front(this);
+        env.gc.push_back(this);
     }
     
     VarSpace::VarSpace(Environment &env_) : env{env_}{
         std::unique_lock<std::mutex> mutex{env.lock};
-        env.gc.push_front(this);
+        env.gc.push_back(this);
     }
 
     VarSpace::~VarSpace() {
         if (getReference() != 0)
             warningLog(aFunCoreLogger, "VarSpace %p destruct reference: %d", this, getReference());
+        std::unique_lock<std::mutex> mutex{env.lock};
+        env.gc.remove(this);
     }
-    
+
+    void Var::linkObject(std::queue<GcObjectBase *> &queue) {
+        queue.push(getData());
+    }
+
     /**
      * 访问指定变量
      * @param name 变量名
@@ -104,6 +113,11 @@ namespace aFuncore {
         var.erase(v);
         return vof_success;
     }
+
+    void VarSpace::linkObject(std::queue<GcObjectBase *> &queue) {
+        for (auto tmp : var)
+            queue.push(tmp.second);
+    }
     
     VarList::VarList(VarList *varlist){
         std::unique_lock<std::mutex> mutex{lock};

+ 20 - 1
test/src/run-code.cpp

@@ -3,6 +3,8 @@
 using namespace aFuncore;
 using namespace aFuntool;
 
+void printInterEvent(Inter &inter);
+
 class Func1 : public Function {
     class CallFunc1 : public CallFunction {
         Code &func_code;
@@ -50,6 +52,16 @@ public:
     }
 
     bool isInfix() override {return true;}
+
+    void destruct(Inter &gc_inter) override {
+        aFuntool::printf_stdout(0, "%p destruct\n", this);
+        auto code = Code("run-code.aun");
+        code.getByteCode()->connect(new Code::ByteCode(code, Code::ByteCode::block_p,
+                                                       new Code::ByteCode(code, "test-var", 1), 0));
+        gc_inter.runCode(code);
+        printInterEvent(gc_inter);
+        fputs_stdout("\n");
+    };
 };
 
 class Literaler1 : public Literaler {
@@ -150,10 +162,17 @@ int Main() {
 
     auto cbv = new CBV1(inter);
     inter.getGlobalVarlist()->defineVar("test-cbv", cbv);
-    aFuntool::cout << "cbv: " << cbv << "\n\n";
+    aFuntool::cout << "cbv: " << cbv << "\n";
     inter.getEnvVarSpace().setNumber("sys:error_std", 1);
     cbv->delReference();
 
+    auto tmp = new Func1(inter);
+    aFuntool::cout << "tmp: " << tmp << "\n\n";
+    tmp->delReference();
+
+    aFuntool::cout << "Checking gc ...\n";
+    aFuntool::safeSleep(3);
+
     {
         fputs_stdout("Test-1: block-p & get test-var\n");
         auto code = Code("run-code.aun");