使用malloc_trim管理Python程序GC问题

使用malloc_trim管理Python程序GC问题Python 带有自动内存管理 使开发人员无需手动处理未分配的对象 与 CPU IO 绑定相比 标准的无状态 Python Web 服务器通常可能受内存限制

大家好,欢迎来到IT知识分享网。

更多互联网新鲜资讯、工作奇淫技巧关注原创【飞鱼在浪屿】(日更新)


许多大型软件-如Instagram,YouTube和Dropbox Web应用程序-最初都是Python应用程序。由于Python的易用性和高质量的开源库,因此使用Python构建Web应用程序极其容易。

使用malloc_trim管理Python程序GC问题


动机

Python带有自动内存管理(带有垃圾回收),使开发人员无需手动处理未分配的对象。这对于更快地交付功能非常有帮助,但是会使应用程序受到内存管理系统和垃圾收集算法的影响。例如,GC暂停在Java等其他托管内存语言中臭名昭著。

速度可能不是Python应用程序的决定性因素,因为它很少用于对性能敏感的应用程序,但是自动内存管理还有其他更微妙的后果。与CPU / IO绑定相比,标准的无状态Python Web服务器(在CPython上运行)通常可能受内存限制。这是因为每个对象都是在堆上分配的,而大型的开源库(例如numpy)仅通过导入在程序中占用约50mb的空间。因此,运行该应用程序的基础架构成本直接与其内存效率-进而与其内存管理紧密相关。这对于其他动态语言(例如PHP和Ruby)也是如此。

一种更有效地运行Python Web服务器的方法是将应用程序的多个进程打包到单个主机(或Pod)上,然后为每个进程设置内存限制(可能通过cgroups设置),以免妨碍其他进程。当进程开始超过其限制时,它会杀死OOM(内存不足)。最后,如果可以降低这些限制,则可以在同一硬件上运行更多进程。这也通过绕过进程而不是线程来启用并发,从而克服了CPython的全局解释器锁(GIL)的局限性。

运行时间长的应用程序还有另一个障碍-即使没有内存泄漏,Python应用程序的内存使用也会在进程生命周期内增加。Python的内存分配器(pymalloc)分配了大型对象,即使由于底层碎片和空闲列表的增长而释放了底层内存,也不一定将它们返回给OS。pymalloc在背后使用malloc,而malloc / free不喜欢过于频繁地将内存返回内核。那么,OOM杀死只是长时间运行的Python应用程序中。

随后,目标变成了两个方面-减少峰值内存使用,以便可以在同一硬件上运行尽可能多的进程,并减少OOM终止的频率,从而不影响应用程序的可用性和可操作性。这意味着OOM终止应该被分开进行(所有进程不应该一起重启),OOM终止应该在足够的间隔(一个小时或更长时间)发生,这样调试进程状态(例如自检应用程序状态)应该不会很困难,并且可以推送/重启由于担心同时进行标准重启和OOM终止,因此该应用程序不需要太多的容量。


malloc_trim

这就是malloc_trim进入的地方。malloc_trim是一个libc函数,它告诉libc将可用内存释放回操作系统。这可能会使随后的分配稍微慢一些,但是如前所述,对于非性能敏感的应用程序,这并不是太多的问题。


如何使用?

malloc_trim非常容易设置。简化的代码示例:

import ctypes import os import psutil def trim_memory() -> int: libc = ctypes.CDLL("libc.so.6") return libc.malloc_trim(0) def should_trim_memory() -> bool: # check if we're close to our OOM limit # through psutil process = psutil.Process(os.getpid()) return process.memory_info().rss > MEMORY_THRESHOLD def trim_loop() -> None: while True: time.sleep(jitter(30, 60)) # jitter between 30 and 60s if not should_trim_memory(): continue ret = trim_memory() print("trim memory result: ", ret) def main() -> None: # run web server thread = Thread(name="TrimThread", target=trim_loop) thread.daemon = True thread.start()

本质上,您在后台运行一个线程来定期要求libc达到阈值时进行清理,例如定期垃圾回收循环。


备择方案

一种替代方法是切换到jemalloc,这是一种尝试减少碎片的替代内存分配器。jemalloc不需要malloc_trim。但是它有缺点,并且并非在所有情况下都有效。

还有一些补充方法,例如__slots__,可以减少Python应用程序的内存使用。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/163567.html

(0)
上一篇 2024-12-20 09:15
下一篇 2024-12-20 09:26

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信