Skip to content

Commit 5596518

Browse files
committed
加入python gc模块。
1 parent f3efdea commit 5596518

File tree

9 files changed

+279
-4
lines changed

9 files changed

+279
-4
lines changed

kbe/src/lib/client_lib/kbemain.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ along with KBEngine. If not, see <http://www.gnu.org/licenses/>.
2929
#include "network/message_handler.hpp"
3030
#include "server/machine_infos.hpp"
3131
#include "server/serverconfig.hpp"
32+
#include "pyscript/py_gc.hpp"
3233
#include "resmgr/resmgr.hpp"
3334
#include "client_lib/config.hpp"
3435

@@ -118,6 +119,8 @@ inline bool installPyScript(KBEngine::script::Script& script, COMPONENT_TYPE com
118119

119120
inline bool uninstallPyScript(KBEngine::script::Script& script)
120121
{
122+
script::PyGC::set_debug(script::PyGC::DEBUG_STATS|script::PyGC::DEBUG_LEAK);
123+
script::PyGC::collect();
121124
client::Entity::uninstallScript();
122125
Entities<client::Entity>::uninstallScript();
123126
EntityGarbages<client::Entity>::uninstallScript();

kbe/src/lib/pyscript/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ SRCS = \
66
map \
77
math \
88
pickler \
9+
py_gc \
910
pystruct \
1011
pyprofile \
1112
pyprofile_handler \

kbe/src/lib/pyscript/pickler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ bool Pickler::initialize(void)
4343
picklerMethod_ = PyObject_GetAttrString(cPickleModule, "dumps");
4444
if (!picklerMethod_)
4545
{
46-
ERROR_MSG("Pickler::initialize:get dumps is error!\n");
46+
ERROR_MSG("Pickler::initialize: get dumps is error!\n");
4747
PyErr_PrintEx(0);
4848
}
4949

@@ -58,7 +58,7 @@ bool Pickler::initialize(void)
5858
}
5959
else
6060
{
61-
ERROR_MSG("can't import pickle!\n");
61+
ERROR_MSG("PyGC::initialize: can't import pickle!\n");
6262
PyErr_PrintEx(0);
6363
}
6464

kbe/src/lib/pyscript/py_gc.cpp

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
/*
2+
This source file is part of KBEngine
3+
For the latest info, see http://www.kbengine.org/
4+
5+
Copyright (c) 2008-2012 KBEngine.
6+
7+
KBEngine is free software: you can redistribute it and/or modify
8+
it under the terms of the GNU Lesser General Public License as published by
9+
the Free Software Foundation, either version 3 of the License, or
10+
(at your option) any later version.
11+
12+
KBEngine is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General Public License
18+
along with KBEngine. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
21+
22+
#include "py_gc.hpp"
23+
#include "helper/profile.hpp"
24+
25+
namespace KBEngine{ namespace script {
26+
27+
PyObject* PyGC::collectMethod_ = NULL;
28+
PyObject* PyGC::set_debugMethod_ = NULL;
29+
30+
uint32 PyGC::DEBUG_STATS = 0;
31+
uint32 PyGC::DEBUG_COLLECTABLE = 0;
32+
uint32 PyGC::DEBUG_UNCOLLECTABLE = 0;
33+
uint32 PyGC::DEBUG_SAVEALL = 0;
34+
uint32 PyGC::DEBUG_LEAK = 0;
35+
36+
bool PyGC::isInit = false;
37+
38+
39+
//-------------------------------------------------------------------------------------
40+
bool PyGC::initialize(void)
41+
{
42+
if(isInit)
43+
return true;
44+
45+
PyObject* gcModule = PyImport_ImportModule("gc");
46+
47+
if(gcModule)
48+
{
49+
collectMethod_ = PyObject_GetAttrString(gcModule, "collect");
50+
if (!collectMethod_)
51+
{
52+
ERROR_MSG("PyGC::initialize: get collect is error!\n");
53+
PyErr_PrintEx(0);
54+
}
55+
56+
set_debugMethod_ = PyObject_GetAttrString(gcModule, "set_debug");
57+
if(!set_debugMethod_)
58+
{
59+
ERROR_MSG("PyGC::init: get set_debug is error!\n");
60+
PyErr_PrintEx(0);
61+
}
62+
63+
PyObject* flag = NULL;
64+
65+
flag = PyObject_GetAttrString(gcModule, "DEBUG_STATS");
66+
if(!flag)
67+
{
68+
ERROR_MSG("PyGC::init: get DEBUG_STATS is error!\n");
69+
PyErr_PrintEx(0);
70+
}
71+
else
72+
{
73+
DEBUG_STATS = PyLong_AsLong(flag);
74+
Py_DECREF(flag);
75+
flag = NULL;
76+
}
77+
78+
flag = PyObject_GetAttrString(gcModule, "DEBUG_COLLECTABLE");
79+
if(!flag)
80+
{
81+
ERROR_MSG("PyGC::init: get DEBUG_COLLECTABLE is error!\n");
82+
PyErr_PrintEx(0);
83+
}
84+
else
85+
{
86+
DEBUG_COLLECTABLE = PyLong_AsLong(flag);
87+
Py_DECREF(flag);
88+
flag = NULL;
89+
}
90+
91+
flag = PyObject_GetAttrString(gcModule, "DEBUG_UNCOLLECTABLE");
92+
if(!flag)
93+
{
94+
ERROR_MSG("PyGC::init: get DEBUG_UNCOLLECTABLE is error!\n");
95+
PyErr_PrintEx(0);
96+
}
97+
else
98+
{
99+
DEBUG_UNCOLLECTABLE = PyLong_AsLong(flag);
100+
Py_DECREF(flag);
101+
flag = NULL;
102+
}
103+
104+
flag = PyObject_GetAttrString(gcModule, "DEBUG_SAVEALL");
105+
if(!flag)
106+
{
107+
ERROR_MSG("PyGC::init: get DEBUG_SAVEALL is error!\n");
108+
PyErr_PrintEx(0);
109+
}
110+
else
111+
{
112+
DEBUG_SAVEALL = PyLong_AsLong(flag);
113+
Py_DECREF(flag);
114+
flag = NULL;
115+
}
116+
117+
flag = PyObject_GetAttrString(gcModule, "DEBUG_LEAK");
118+
if(!flag)
119+
{
120+
ERROR_MSG("PyGC::init: get DEBUG_LEAK is error!\n");
121+
PyErr_PrintEx(0);
122+
}
123+
else
124+
{
125+
DEBUG_LEAK = PyLong_AsLong(flag);
126+
Py_DECREF(flag);
127+
flag = NULL;
128+
}
129+
130+
Py_DECREF(gcModule);
131+
}
132+
else
133+
{
134+
ERROR_MSG("PyGC::initialize: can't import gc!\n");
135+
PyErr_PrintEx(0);
136+
}
137+
138+
isInit = collectMethod_ && set_debugMethod_;
139+
return isInit;
140+
}
141+
142+
//-------------------------------------------------------------------------------------
143+
void PyGC::finalise(void)
144+
{
145+
Py_XDECREF(collectMethod_);
146+
Py_XDECREF(set_debugMethod_);
147+
148+
collectMethod_ = NULL;
149+
set_debugMethod_ = NULL;
150+
}
151+
152+
//-------------------------------------------------------------------------------------
153+
void PyGC::collect(int8 generations)
154+
{
155+
PyObject* pyRet = NULL;
156+
157+
if(generations != -1)
158+
{
159+
pyRet = PyObject_CallFunction(collectMethod_,
160+
const_cast<char*>("(i)"), generations);
161+
}
162+
else
163+
{
164+
pyRet = PyObject_CallFunction(collectMethod_,
165+
const_cast<char*>(""));
166+
}
167+
168+
SCRIPT_ERROR_CHECK();
169+
170+
if(pyRet)
171+
{
172+
S_RELEASE(pyRet);
173+
}
174+
}
175+
176+
//-------------------------------------------------------------------------------------
177+
void PyGC::set_debug(uint32 flsgs)
178+
{
179+
PyObject* pyRet = PyObject_CallFunction(collectMethod_,
180+
const_cast<char*>("(i)"), flsgs);
181+
182+
SCRIPT_ERROR_CHECK();
183+
184+
if(pyRet)
185+
{
186+
S_RELEASE(pyRet);
187+
}
188+
}
189+
190+
//-------------------------------------------------------------------------------------
191+
192+
}
193+
}

kbe/src/lib/pyscript/py_gc.hpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
This source file is part of KBEngine
3+
For the latest info, see http://www.kbengine.org/
4+
5+
Copyright (c) 2008-2012 KBEngine.
6+
7+
KBEngine is free software: you can redistribute it and/or modify
8+
it under the terms of the GNU Lesser General Public License as published by
9+
the Free Software Foundation, either version 3 of the License, or
10+
(at your option) any later version.
11+
12+
KBEngine is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General Public License
18+
along with KBEngine. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
21+
#ifndef KBE_PY_GC_HPP
22+
#define KBE_PY_GC_HPP
23+
24+
#include "cstdkbe/cstdkbe.hpp"
25+
#include "scriptobject.hpp"
26+
27+
namespace KBEngine{ namespace script{
28+
29+
class PyGC
30+
{
31+
public:
32+
static uint32 DEBUG_STATS;
33+
static uint32 DEBUG_COLLECTABLE;
34+
static uint32 DEBUG_UNCOLLECTABLE;
35+
static uint32 DEBUG_SAVEALL;
36+
static uint32 DEBUG_LEAK;
37+
38+
/**
39+
初始化pickler
40+
*/
41+
static bool initialize(void);
42+
static void finalise(void);
43+
44+
/**
45+
强制回收垃圾
46+
*/
47+
static void collect(int8 generations = -1);
48+
49+
/**
50+
设置调试标志
51+
*/
52+
static void set_debug(uint32 flsgs);
53+
54+
private:
55+
static PyObject* collectMethod_; // cPicket.dumps方法指针
56+
static PyObject* set_debugMethod_; // cPicket.loads方法指针
57+
58+
static bool isInit; // 是否已经被初始化
59+
} ;
60+
61+
}
62+
}
63+
64+
#endif // KBE_PY_GC_HPP

kbe/src/lib/pyscript/pyscript.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
<ClCompile Include="map.cpp" />
9999
<ClCompile Include="math.cpp" />
100100
<ClCompile Include="pickler.cpp" />
101+
<ClCompile Include="py_gc.cpp" />
101102
<ClCompile Include="py_memorystream.cpp" />
102103
<ClCompile Include="pyprofile.cpp" />
103104
<ClCompile Include="pyprofile_handler.cpp" />
@@ -118,6 +119,7 @@
118119
<ClInclude Include="map.hpp" />
119120
<ClInclude Include="math.hpp" />
120121
<ClInclude Include="pickler.hpp" />
122+
<ClInclude Include="py_gc.hpp" />
121123
<ClInclude Include="py_memorystream.hpp" />
122124
<ClInclude Include="pyattr_macro.hpp" />
123125
<ClInclude Include="pyobject_call_template.hpp" />

kbe/src/lib/pyscript/pyscript.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
<ClCompile Include="vector4.cpp">
7070
<Filter>Source Files</Filter>
7171
</ClCompile>
72+
<ClCompile Include="py_gc.cpp">
73+
<Filter>Source Files</Filter>
74+
</ClCompile>
7275
</ItemGroup>
7376
<ItemGroup>
7477
<ClInclude Include="copy.hpp">
@@ -137,6 +140,9 @@
137140
<ClInclude Include="vector4.hpp">
138141
<Filter>Header Files</Filter>
139142
</ClInclude>
143+
<ClInclude Include="py_gc.hpp">
144+
<Filter>Header Files</Filter>
145+
</ClInclude>
140146
</ItemGroup>
141147
<ItemGroup>
142148
<None Include="map.ipp" />

kbe/src/lib/pyscript/script.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ along with KBEngine. If not, see <http://www.gnu.org/licenses/>.
2525
#include "pyprofile.hpp"
2626
#include "copy.hpp"
2727
#include "pystruct.hpp"
28+
#include "py_gc.hpp"
2829
#include "install_py_dlls.hpp"
2930
#include "resmgr/resmgr.hpp"
3031
#include "thread/concurrency.hpp"
@@ -228,6 +229,7 @@ bool Script::install(const wchar_t* pythonHomeDir, std::wstring pyPaths,
228229
return false;
229230
}
230231

232+
PyGC::initialize();
231233
Pickler::initialize();
232234
PyProfile::initialize(this);
233235
PyStruct::initialize();
@@ -247,11 +249,11 @@ bool Script::uninstall()
247249
PyProfile::finalise();
248250
PyStruct::finalise();
249251
Copy::finalise();
250-
SCRIPT_ERROR_CHECK(); // 检查是否有错误产生
252+
SCRIPT_ERROR_CHECK();
251253

252254
if(pyStdouterr_)
253255
{
254-
if(pyStdouterr_->isInstall() && !pyStdouterr_->uninstall()) { // 卸载py重定向脚本模块
256+
if(pyStdouterr_->isInstall() && !pyStdouterr_->uninstall()) {
255257
ERROR_MSG("Script::uninstall(): pyStdouterr_->uninstall() is failed!\n");
256258
}
257259
else
@@ -284,6 +286,7 @@ bool Script::uninstall()
284286
}
285287
#endif
286288

289+
PyGC::initialize();
287290
Py_Finalize(); // 卸载python解释器
288291
INFO_MSG("Script::uninstall(): is successfully!\n");
289292
return true;

kbe/src/lib/server/entity_app.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ along with KBEngine. If not, see <http://www.gnu.org/licenses/>.
2222
#define KBE_ENTITY_APP_HPP
2323

2424
// common include
25+
#include "pyscript/py_gc.hpp"
2526
#include "pyscript/script.hpp"
2627
#include "pyscript/pyprofile.hpp"
2728
#include "pyscript/pyprofile_handler.hpp"
@@ -533,6 +534,8 @@ bool EntityApp<E>::installPyModules()
533534
template<class E>
534535
bool EntityApp<E>::uninstallPyModules()
535536
{
537+
script::PyGC::set_debug(script::PyGC::DEBUG_STATS|script::PyGC::DEBUG_LEAK);
538+
script::PyGC::collect();
536539
unregisterPyObjectToScript("globalData");
537540
S_RELEASE(pGlobalData_);
538541

0 commit comments

Comments
 (0)