有个计算机专业的学妹问我:我这个zip文件密码破解运行起来为什么内存爆了?

1.这篇博文的由来

有个计算机专业的学妹问我:我这个zip文件密码破解运行起来为什么内存爆了?

2.跑下错误代码,找病根

先把学妹发给我的错误代码放上,能发现他为了提高速度加了多线程的代码,很聪明哦:

import zipfile
import itertools
from concurrent.futures import ThreadPoolExecutor def extract(file, password):
if not flag: return
file.extractall(path='.', pwd=''.join(password).encode('utf-8')) def result(f):
exception = f.exception()
if not exception:
print('密码为:', f.pwd)
global flag
flag = False if __name__ == '__main__':
flag = True
pool = ThreadPoolExecutor(100)
nums = [str(i) for i in range(10)]
chrs = [chr(i) for i in range(65, 91)]
password_lst = itertools.permutations(nums + chrs, 6)
zfile = zipfile.ZipFile("加密文件.zip", 'r')
for pwd in password_lst:
if not flag: break
f = pool.submit(extract, zfile, pwd)
f.pwd = pwd
f.pool = pool
f.add_done_callback(result)

用他的代码跑一下,乖乖隆地咚~跑一会儿内存就爆了。

那么原因是因为:ThreadPoolExecutor默认使用的是*队列,尝试密码的速度跟不上生产密码的速度,会把生产任务无限添加到队列中,导致内存被占满。

展示下,内存直接飙到95: 有个计算机专业的学妹问我:我这个zip文件密码破解运行起来为什么内存爆了?

然后导致程序崩溃:

有个计算机专业的学妹问我:我这个zip文件密码破解运行起来为什么内存爆了?

3.找到病根,对症下药

修改下源码,发现ThreadPoolExecutor内部使用的是*队列,所以导致内存直接飙满,重写ThreadPoolExecutor类中的_work_queue属性,将*队列改成有界队列,这样就不会出现内存爆满的问题,看代码:

import queue
from concurrent.futures import ThreadPoolExecutor class BoundedThreadPoolExecutor(ThreadPoolExecutor):
def __init__(self, max_workers=None, thread_name_prefix=''):
super().__init__(max_workers, thread_name_prefix)
self._work_queue = queue.Queue(self._max_workers * 2) # 设置队列大小

最后学妹按我给他的建议,完美的破解密码成功。

点击领取干货满满

感谢观看,关注我持续为您分享干货内容,你的收藏、评论、点赞就是对我最大的支持! 需要领取我之前学习资料的可以私信我,告诉我你具体需要的资料。

上一篇:Java中的ExceptionInInitializerError异常及解决方法


下一篇:Python3基础 list count 查询指定元素在列表中出现了多少次