-
Notifications
You must be signed in to change notification settings - Fork 115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
un_serialize增加开关以避免读取特定文件末尾512字节时会导致内存暴涨的问题 #65
Comments
DNF蚊子腿小助手_增量更新文件_v13.11.0_to_v13.13.0.zip 记得改名为 DNF蚊子腿小助手_增量更新文件_v13.11.0_to_v13.13.0.7z |
在 Windows10 和 Linux 上面测试了多次都没有发现内存泄漏的问题。
|
我感觉loads里面可能会根据字节码来进行各种操作,比如上面这个情况可能是误解析为一个很大的数组之类的了? |
pickle官方文档看到这么一段话,感觉可能就是这个原因-。-
|
我刚刚测试这个文件好像也没了,有点奇怪,难道跟文件本身以外的东西还有关= = |
前天是在家里的电脑重现的-。-刚刚在公司电脑上确实没重现出来,我回家再看看能否重现,如果可以重现就把最后512字节打印出来,看看是啥问题 |
重新试了下,在家里的电脑上直接运行、wsl中运行、docker中运行均会出现这种情况,在公司的电脑中,直接运行没事,在wsl中运行会出现问题。怀疑是需要电脑内存超过34G(家中内存为64G,公司为32G),否则在申请内存时会直接提前被killed 新的精简后的测试代码 import multiprocessing
import pickle
import pickletools
import platform
import time
import psutil
def print_memory_info():
info = psutil.virtual_memory()
print(f"memory info: svmem(total={info.total}, available={info.available}, percent={info.percent}, used={info.used}, free={info.free})")
def print_memory_usage_every_seconds(total_time=10):
for i in range(total_time):
print_memory_info()
time.sleep(1)
if __name__ == '__main__':
multiprocessing.freeze_support()
print(f"test on {platform.uname()}")
print_memory_info()
multiprocessing.Process(target=print_memory_usage_every_seconds, daemon=True).start()
last_512_bytes = b']r(\xad\xad\x85\x91\x05\xe5s2T\xcb/\xf8\xbd\xf2\x03\xc2\x10\x88\xb5\xf6\x8a\xd7\xd7\xc1\x08\xe5`V!p\x13"\x01\x81A\xa6o\x95\x13M\x18I\xce\x02q\xcf\xd5l\xda{\xb2\x03\xa4\x07L\xc4\x86\xf6\x1f\x96\xdb+\xb0\xd9\x1e6\xd4\x9ed\xdfU\xd3\xf5S\x1a7\xe4\x03\xfd\xfc(\xda\x1f\x95\x01\xb7$af3\xcbs\xef\xda*\xcf1D\x88,[\xe3^#h\xd3\xd3-\x0bw&\n%\xae\x95Wf\xf9n\xed\xb3\x99\x082>\xa4XC\xbc3\x8d\x81?\x95\t\xe2c\xd8\xfc\xc0\x89\x1e\x8b wX\xbb\xe3!\x90RK\x17K\x03\xe5Y\x9c\x06\x18\xb9By\t\xb3-F\x90\xd5p\xf9@E\xf9\xf8\t\x1eAC\\\'\x16\xeaE:+zV\x93+\x1d\x92\xdc\x14}`!.t\xcf"\x14\xdb\xf1\xeb\xc1\xe4q`\xfa\x9b\xee\xa9(Vo]\x0b1zy\x80\xc4\x8d\xac?\xf5\r\xe8\xbc\xf8\x1c\x07,\xc4\xc6:\xb8\xab\x1d%\xaf\x9c\xfb*\xf6\xe4\xcc\xcai\x02.]\x7fB\x83\x13\xd9\xd6d\xe1Ew\xf2\xe5\x7f\xe0\x81\xdd\'\xa88c\x90L\x00\x05\x03\xec\xbeY\x00\x00\x00\x813\x07\xae\x0f\xd8\xb6\t\xe6*\x8cH\xa7\xca\xe4(yi\x85\x8a~\x01\x08\xdc\xa0\xc9\x02?v1\xa7\xd6\r\xb7\xaf\xd9\x03\xdet\xaa\x03a\xf6w0c9^\x19\xd8\x17\xa6pL\x01:\xaa\x8d\xda\xdcR\x8f\xa7\xa4\xb3C4\x94\xe7\xea\x12\\Q\x8f\x91\x0e\x99\xf6\xbcz\x16\xc0NP\xdc\x0cF&\x9fkB\xfa\x10\xba^T\xf4\xf1\t\xefy\'\x8d+}\x83Zt\x9d\xd4\x94\xd2\x88\xdcc\xf9\xfb^\xc3\x03\x15\x8c\xa6|\xc0\xf1O_/#o\xc3\xad\x06\xbe\x1c%\x04 &\x85\x1a\xa8p.\xc0(\x1b}\xb7\xfdD\x8b`+\xc7Z\xf5\x9dx\xc2i\x8eu\x0e\xb2\xea\x85"h\x96\x0b\x06\x8e\xe7\xc1C\xcd\xafU\\\x97&\x97*Q\xa6O\xbe\x17\x06\xd2\x8a>\x01\t\x80\xbf\x00\x07\x0b\x01\x00\x01#\x03\x01\x01\x05]\x00\x00\x10\x00\x0c\x81\xfa\n\x01\xcf\x12_\xe2\x00\x00'
try:
pickletools.dis(last_512_bytes)
except Exception as e:
print(f"excep={e}")
try:
pickle.loads(last_512_bytes)
except Exception as e:
print(f"excep={e}") 家中直接运行结果 (X)
家中wsl运行结果 (X)
家中docker运行 (X) -- docker run --rm fzls/debug
公司电脑直接运行 (O)
公司wsl运行 (X)
公司docker运行 (X) -- docker run --rm fzls/debug
|
根据pickletools的分析结果,应该是这段字节码被解析为创建一个2242751784大小的列表,导致最终消耗大量内存?如果内存足够的时候会进行创建,而内存不足时则会提前kill或者直接不分配内存直接抛异常 相关的opcode说明 |
试一试这个 https://github.com/zaxtyson/LanZouCloud-API/tree/fix-65 |
你这个分支好像还没提交东西哇-。-是准备先用pickletools去解析这段二进制,确保不会抛出异常,是正常的pickle序列化结果后再尝试使用pickle.loads吗0-0 |
如果是上面这样,至少可以把这种【非pickle序列化出来的内容,但是前面部分字节码可以正常解析,后面无法正常解析,而正常解析的这部分可能是任何行为】的情况给排除掉。一般不是pickle序列化出来的512字节,能完全符合pickle的协议的概率应该是微乎其微的,这样基本就能确保这512字节是我们上传时特地写进去的了 |
又稍微改了一下,这种碰巧的情况应该不会遇到了 |
问题说明
目前在下载完文件时,如果这个文件大于512字节,会尝试对其末尾512字节使用pickle.loads函数进行解析,如果未曾编码过,在特定文件内容时,这个函数有可能会造成大量调用内存,比如下面这个例子中会占用34G的内存。
示例
示例文件网盘链接:https://fzls.lanzoui.com/iwnVktkr9je
若链接失效,可直接下载附件文件自行上传后得到新的链接
示例代码
现象
![Snipaste_2021-09-06_00-24-31](https://user-images.githubusercontent.com/13483212/132134287-0adb47e8-fb65-4520-9541-860b4dfb06a0.png)
修复办法
api/utils.py中增加开关,比如直接复用self._limit_mode,从而在确定不会使用额外编码来绕开官方限制的情况下(不调用ignore_limits的情况下)不会尝试使用pickle解析文件末尾512字节
原来代码
调整后代码
The text was updated successfully, but these errors were encountered: