Python中的内存泄漏

内存泄漏是一个常见的编程问题,可能很难调试和修复。

本文将通过小型和大型的示例程序探讨Python的内存泄漏问题。我们将看到如何找到内存泄漏的来源以及如何修复它。

Python中的内存泄漏

我们不会在本文中讨论Python内存管理系统的内部情况。但是,如果你对Python内存系统如何工作感到好奇,你可以参考Python标准库的源代码和其他高级编程语言的代码。

现在,让我们讨论一些库,我们将在我们的例子中使用这些库来研究Python的内存泄漏。第一个库是Requests库,它允许我们对一个特定的URL进行HTTP请求。

在推进这些技术之前,无论是REST APIs还是Web Scraping,都必须学会Requests。当一个请求被发送到一个URL时,会返回一个响应。

Python应用程序包含请求和响应的内置管理功能。

我们可以使用以下命令轻松地安装它。

# python
pip install requests

一旦我们安装了requests 库,现在我们将安装GC模块。它使我们能够访问Python垃圾收集器。

它有激活收集器、禁用收集器、调整收集频率、调试等选项。

在像C和C++这样的低级语言中,程序员必须手动释放任何不再使用的资源。换个说法,就是开发编程来管理资源。

然而,像Python和Java这样的高级语言包含一个垃圾收集的概念,即自动化的内存管理。垃圾收集负责为一个程序分配和释放内存。

我们将使用的GC模块的方法有:get_object() ,该方法从垃圾收集中给出被跟踪的对象。我们还将使用collect() 方法,从收集器控制的列表中提供非引用对象的释放。

识别Python中的内存泄漏

现在,我们将讨论如何在运行程序时识别是否有内存泄漏。让我们从一个例子开始,使用上面提到的库来检查是否有泄漏。

我们将首先导入这个例子中前面提到的库。

# python
import requests
import gc

然后我们将定义一个函数,getGoogle() ,它将使用Requests库向google.com 请求响应,并返回收到的状态代码。

代码:

# python
def getGoogle():
    resultGot = requests.get('https://google.com')
    print("Status Code recieved is ", resultGot.status_code)
    return

现在我们将定义另一个函数,checkMemoryLeak() ,其中我们将在调用函数getGoogle() 之前和之后收集垃圾对象。

代码:

# python
def checkMemoryLeak():
    print("Memory Leaked before calling getGoogle()")
    print(len( gc.get_objects() ) )
    getGoogle()
    print("Memory Leaked before calling getGoogle()")
    print(len( gc.get_objects() ) )
checkMemoryLeak()

输出:

Python中的内存泄漏

正如你在例子中看到的,在调用函数之前,垃圾收集器的长度是17472,而在调用我们的函数之后,长度增加到17698。这表明,在执行一些任务时,总是有内存泄漏。

现在我们将讨论如何修复内存泄漏,并在没有内存泄漏的情况下尽可能多地收集数据。

修复Python中的内存泄漏

我们可以使用函数gc.collect() 在Python中修复内存泄漏。我们将使用相同的程序,但对其进行修改,以便没有或尽量减少内存泄漏。

在这个例子中,在调用我们的函数getGoogle() 之后,我们将直接调用gc.collect() ,这将减少内存泄漏并解决这个问题。

代码:

# python
import requests
import gc
def getGoogle():
    resultGot = requests.get('https://google.com')
    print("Status Code recieved is ", resultGot.status_code)
def checkMemoryLeak():
    print("Memory Leaked before calling getGoogle()")
    print(len( gc.get_objects() ) )
    getGoogle()
    gc.collect()
    print("Memory Leaked before calling getGoogle()")
    print(len( gc.get_objects() ) )
checkMemoryLeak()

输出:

Python中的内存泄漏

正如你在例子中看到的,使用gc.collect() 之后,内存泄漏的数量减少了。所以通过这种方式,我们可以在函数调用过程中防止内存泄露。