python内存处理和常见的内存泄漏场景
python内存处理和常见的内存泄漏场景
一 python内存处理机制
手动垃圾回收:采用gc.collect()进行手动强制执行垃圾回收,采用变量赋值为空,等待下一轮python自动回收,采用del变量,直接删除
**引用计数(reference count):**垃圾回收机制会记录每个对象被其他对象所引用的次数。
**循环引用检测:**若对象之间存在相互引用,则对象间将形成一个环状结构,使得引用计数不会降为零,因此内存无法被自动回收,导致内存泄漏。
二常见的内存泄漏常见
1.循环引用:当两个或多个对象互相引用彼此时,它们之间就会形成一个循环。这样会导致 Python 的垃圾回收机制无法释放这些对象所占用的内存空间;
class LeakClass:
def __init__(self):
self.other_object = None
instance_a = LeakClass()
instance_b = LeakClass()
# 循环引用,导致内存泄露
instance_a.other_object = instance_b
instance_b.other_object = instance_a
2.全局变量和缓存:如果程序中有大量的全局变量和缓存,那么这些对象可能不会被垃圾回收器正确地释放。
cache = {}
def add_to_cache(key, value):
global cache
cache[key] = value
# 不断添加元素到缓存,导致内存泄露
for i in range(100000):
add_to_cache(i, "value")
3.未关闭文件句柄:如果程序中打开了文件但没有及时关闭,那么这些文件句柄会一直占用内存直到程序退出。
# 打开文件,但未关闭文件句柄,导致内存泄露
file_handle = open("myfile.txt", "w")
4.计数器引用: 当一个对象的引用计数不正确时,会导致垃圾回收器无法正确地释放该对象的内存空间。这种情况通常会发生在使用 ctypes 库时。
import ctypes
def leaking_func(self):
self.buffer = (ctypes.c_char * 1024)()
# 计数器引用,导致内存泄露
while True:
leaking_func()
5.长期运行的循环:
def long_running_loop():
while True:
pass
# 长期运行的循环,会一直占用内存
long_running_loop()
6.大型数据结构的未释放:
def load_data():
data = [i for i in range(1000000)]
return data
# 调用函数获取大型数据结构,但不及时释放,导致内存泄露
big_data = load_data()
7.信号处理:
import signal
def handle_signal(signum, frame):
pass
# 注册信号处理函数,但不移除导致内存泄露
signal.signal(signal.SIGUSR1, handle_signal)
8.外部资源的未释放:
import sqlite3
# 打开数据库连接,但不关闭连接,导致内存泄露
conn = sqlite3.connect('mydatabase.db')
9.循环中的生成器:
def generator():
# 生成器函数
for i in range(1000000):
yield i
# 循环遍历生成器,但不释放引用,导致内存泄露
for item in generator():
pass
10.不正确使用多进程和多线程:
import multiprocessing
import threading
def target_thread():
while True:
pass
# 创建多个进程或线程,但不关闭或结束,导致内存泄露
for i in range(2):
multiprocessing.Process(target=target_thread).start()
for i in range(2):
threading.Thread(target=target_thread).start()
11.滥用缓存:
cache = {}
def heavy_data_processing(input_data):
# 需要费时地处理的数据
output_data = input_data * 2
return output_data
# 存储完整数据,而非必须的中间输出,导致内存泄露
while True:
data = load_data()
if data in cache:
output = cache[data]
else:
output = heavy_data_processing(data)
cache[data] = output
12.滥用全局变量:
def global_state_changing():
global global_data
global_data += 1
# 不断更改全局状态,导致内存泄露
while True:
global_state_changing()
13.大量异常创建:
def exception_raising():
raise Exception("Errors")
# 大量的异常创建,但并不处理异常,导致内存泄露
while True:
try:
exception_raising()
except:
pass