customserver: fix memory leak (#3864)
This commit is contained in:
parent
34a3b5f058
commit
1a41e1acc8
|
@ -67,6 +67,21 @@ def update_dict(dictionary, entries):
|
||||||
return dictionary
|
return dictionary
|
||||||
|
|
||||||
|
|
||||||
|
def queue_gc():
|
||||||
|
import gc
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
gc_thread: typing.Optional[Thread] = getattr(queue_gc, "_thread", None)
|
||||||
|
def async_collect():
|
||||||
|
time.sleep(2)
|
||||||
|
setattr(queue_gc, "_thread", None)
|
||||||
|
gc.collect()
|
||||||
|
if not gc_thread:
|
||||||
|
gc_thread = Thread(target=async_collect)
|
||||||
|
setattr(queue_gc, "_thread", gc_thread)
|
||||||
|
gc_thread.start()
|
||||||
|
|
||||||
|
|
||||||
# functions callable on storable data on the server by clients
|
# functions callable on storable data on the server by clients
|
||||||
modify_functions = {
|
modify_functions = {
|
||||||
# generic:
|
# generic:
|
||||||
|
@ -551,6 +566,9 @@ class Context:
|
||||||
self.logger.info(f"Saving failed. Retry in {self.auto_save_interval} seconds.")
|
self.logger.info(f"Saving failed. Retry in {self.auto_save_interval} seconds.")
|
||||||
else:
|
else:
|
||||||
self.save_dirty = False
|
self.save_dirty = False
|
||||||
|
if not atexit_save: # if atexit is used, that keeps a reference anyway
|
||||||
|
queue_gc()
|
||||||
|
|
||||||
self.auto_saver_thread = threading.Thread(target=save_regularly, daemon=True)
|
self.auto_saver_thread = threading.Thread(target=save_regularly, daemon=True)
|
||||||
self.auto_saver_thread.start()
|
self.auto_saver_thread.start()
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,14 @@ class WebHostContext(Context):
|
||||||
self.video = {}
|
self.video = {}
|
||||||
self.tags = ["AP", "WebHost"]
|
self.tags = ["AP", "WebHost"]
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
try:
|
||||||
|
import psutil
|
||||||
|
from Utils import format_SI_prefix
|
||||||
|
self.logger.debug(f"Context destroyed, Mem: {format_SI_prefix(psutil.Process().memory_info().rss, 1024)}iB")
|
||||||
|
except ImportError:
|
||||||
|
self.logger.debug("Context destroyed")
|
||||||
|
|
||||||
def _load_game_data(self):
|
def _load_game_data(self):
|
||||||
for key, value in self.static_server_data.items():
|
for key, value in self.static_server_data.items():
|
||||||
# NOTE: attributes are mutable and shared, so they will have to be copied before being modified
|
# NOTE: attributes are mutable and shared, so they will have to be copied before being modified
|
||||||
|
@ -249,6 +257,7 @@ def run_server_process(name: str, ponyconfig: dict, static_server_data: dict,
|
||||||
ctx = WebHostContext(static_server_data, logger)
|
ctx = WebHostContext(static_server_data, logger)
|
||||||
ctx.load(room_id)
|
ctx.load(room_id)
|
||||||
ctx.init_save()
|
ctx.init_save()
|
||||||
|
assert ctx.server is None
|
||||||
try:
|
try:
|
||||||
ctx.server = websockets.serve(
|
ctx.server = websockets.serve(
|
||||||
functools.partial(server, ctx=ctx), ctx.host, ctx.port, ssl=ssl_context)
|
functools.partial(server, ctx=ctx), ctx.host, ctx.port, ssl=ssl_context)
|
||||||
|
@ -279,6 +288,7 @@ def run_server_process(name: str, ponyconfig: dict, static_server_data: dict,
|
||||||
ctx.auto_shutdown = Room.get(id=room_id).timeout
|
ctx.auto_shutdown = Room.get(id=room_id).timeout
|
||||||
if ctx.saving:
|
if ctx.saving:
|
||||||
setattr(asyncio.current_task(), "save", lambda: ctx._save(True))
|
setattr(asyncio.current_task(), "save", lambda: ctx._save(True))
|
||||||
|
assert ctx.shutdown_task is None
|
||||||
ctx.shutdown_task = asyncio.create_task(auto_shutdown(ctx, []))
|
ctx.shutdown_task = asyncio.create_task(auto_shutdown(ctx, []))
|
||||||
await ctx.shutdown_task
|
await ctx.shutdown_task
|
||||||
|
|
||||||
|
@ -325,7 +335,7 @@ def run_server_process(name: str, ponyconfig: dict, static_server_data: dict,
|
||||||
def run(self):
|
def run(self):
|
||||||
while 1:
|
while 1:
|
||||||
next_room = rooms_to_run.get(block=True, timeout=None)
|
next_room = rooms_to_run.get(block=True, timeout=None)
|
||||||
gc.collect(0)
|
gc.collect()
|
||||||
task = asyncio.run_coroutine_threadsafe(start_room(next_room), loop)
|
task = asyncio.run_coroutine_threadsafe(start_room(next_room), loop)
|
||||||
self._tasks.append(task)
|
self._tasks.append(task)
|
||||||
task.add_done_callback(self._done)
|
task.add_done_callback(self._done)
|
||||||
|
|
Loading…
Reference in New Issue