python中显存回收问题解决方法
作者:Dechin's 发布时间:2022-06-28 03:06:29
目录
1.技术背景
2.问题复现
3.解决思路
4.总结概要
1.技术背景
笔者在执行一个Jax的任务中,又发现了一个奇怪的问题,就是明明只分配了很小的矩阵空间,但是在多次的任务执行之后,显存突然就爆了。而且此时已经按照Jax的官方说明配置了XLA_PYTHON_CLIENT_PREALLOCATE
这个参数为false,也就是不进行显存的预分配(默认会分配90%的显存空间以供使用)。然后在网上找到了一些类似的问题,比如参考链接中的1、2、3、4,都是在一些操作后发现未释放显存,这里提供一个实例问题和处理的思路,如果有更好的方案欢迎大家在评论区留言。
2.问题复现
在未执行任何GPU的任务时,我们可以看到此时nvidia-smi的输出如下:
Tue Dec 14 16:14:32 2021
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 470.42.01 Driver Version: 470.42.01 CUDA Version: 11.4 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 Quadro RTX 4000 On | 00000000:03:00.0 On | N/A |
| 30% 43C P8 20W / 125W | 1260MiB / 7979MiB | 10% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 1 Quadro RTX 4000 On | 00000000:A6:00.0 Off | N/A |
| 30% 34C P8 7W / 125W | 10MiB / 7982MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| 0 N/A N/A 1673 G /usr/lib/xorg/Xorg 110MiB |
| 0 N/A N/A 3015 G /usr/lib/xorg/Xorg 661MiB |
| 0 N/A N/A 3251 G /usr/bin/gnome-shell 132MiB |
| 0 N/A N/A 1142734 G ...AAAAAAAAA= --shared-files 64MiB |
| 0 N/A N/A 1337710 G ...AAAAAAAAA= --shared-files 80MiB |
| 0 N/A N/A 1371509 G ...369783.log --shared-files 63MiB |
| 0 N/A N/A 1506625 G ...AAAAAAAAA= --shared-files 89MiB |
| 1 N/A N/A 1673 G /usr/lib/xorg/Xorg 4MiB |
| 1 N/A N/A 3015 G /usr/lib/xorg/Xorg 4MiB |
+-----------------------------------------------------------------------------+
此时启动一个ipython的终端窗口,执行如下的Jax任务:
In [1]: import numpy as np
In [2]: import os
...: os.environ['CUDA_VISIBLE_DEVICES']='1'
...: os.environ["XLA_PYTHON_CLIENT_PREALLOCATE"] = "false"
In [3]: from jax import numpy as jnp
In [4]: a = np.ones(1000000)
In [5]: b = jnp.array(a)
此时再次查看nvidia-smi的结果如下:
Tue Dec 14 16:18:26 2021
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 470.42.01 Driver Version: 470.42.01 CUDA Version: 11.4 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 Quadro RTX 4000 On | 00000000:03:00.0 On | N/A |
| 30% 42C P8 20W / 125W | 1238MiB / 7979MiB | 10% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 1 Quadro RTX 4000 On | 00000000:A6:00.0 Off | N/A |
| 30% 36C P0 35W / 125W | 114MiB / 7982MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| 0 N/A N/A 1673 G /usr/lib/xorg/Xorg 110MiB |
| 0 N/A N/A 3015 G /usr/lib/xorg/Xorg 661MiB |
| 0 N/A N/A 3251 G /usr/bin/gnome-shell 129MiB |
| 0 N/A N/A 1142734 G ...AAAAAAAAA= --shared-files 44MiB |
| 0 N/A N/A 1337710 G ...AAAAAAAAA= --shared-files 80MiB |
| 0 N/A N/A 1371509 G ...369783.log --shared-files 63MiB |
| 0 N/A N/A 1506625 G ...AAAAAAAAA= --shared-files 89MiB |
| 1 N/A N/A 1673 G /usr/lib/xorg/Xorg 4MiB |
| 1 N/A N/A 3015 G /usr/lib/xorg/Xorg 4MiB |
| 1 N/A N/A 1743467 C /usr/local/bin/python 101MiB |
+-----------------------------------------------------------------------------+
此时的结果还是比较符合我们的预期的,这个python的进程占用了101MB的空间。但是此时如果我们在ipython中把这个对象删除了:
In [6]: del b
In [7]: b
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-7-89e6c98d9288> in <module>
----> 1 b
NameError: name 'b' is not defined
然后再次查看nvidia-smi的结果:
Tue Dec 14 16:21:12 2021
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 470.42.01 Driver Version: 470.42.01 CUDA Version: 11.4 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 Quadro RTX 4000 On | 00000000:03:00.0 On | N/A |
| 30% 42C P5 21W / 125W | 1231MiB / 7979MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 1 Quadro RTX 4000 On | 00000000:A6:00.0 Off | N/A |
| 30% 35C P8 7W / 125W | 114MiB / 7982MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| 0 N/A N/A 1673 G /usr/lib/xorg/Xorg 110MiB |
| 0 N/A N/A 3015 G /usr/lib/xorg/Xorg 662MiB |
| 0 N/A N/A 3251 G /usr/bin/gnome-shell 111MiB |
| 0 N/A N/A 1142734 G ...AAAAAAAAA= --shared-files 55MiB |
| 0 N/A N/A 1337710 G ...AAAAAAAAA= --shared-files 80MiB |
| 0 N/A N/A 1371509 G ...369783.log --shared-files 63MiB |
| 0 N/A N/A 1506625 G ...AAAAAAAAA= --shared-files 89MiB |
| 1 N/A N/A 1673 G /usr/lib/xorg/Xorg 4MiB |
| 1 N/A N/A 3015 G /usr/lib/xorg/Xorg 4MiB |
| 1 N/A N/A 1743467 C /usr/local/bin/python 101MiB |
+-----------------------------------------------------------------------------+
此时我们可以看到,虽然已经把对象给删除了,在python的程序中已然找不到这个对象,但是在显存中的数据并未被消除。而且如果一直不消除,这块显存就会一直占用在那里,直到python
进程(此时作为该进程的一个守护进程)的结束。
3.解决思路
暂时还不清楚这个问题发生的机制,在一些特定场景下出现僵尸进程的问题似乎跟我复现的这个场景也有所不同。只是考虑到在python的进程结束之后,这一块的显存还是被成功释放了的,因此我考虑直接用进程的方法来解决这个显存分配和清空的方法,以下是一个基于进程实现的案例:
import os
os.environ['CUDA_VISIBLE_DEVICES']='1'
os.environ["XLA_PYTHON_CLIENT_PREALLOCATE"] = "false"
import time
from multiprocessing import Pool
import numpy as np
from jax import numpy as jnp
a = np.ones(1000000)
def f(a):
b = jnp.array(a)
time.sleep(2)
print('Array b has been deleted!')
return True
with Pool(1) as p:
res = p.map(f, [(a,)])
print ('Is jax array deleted successfully?\t{}'.format(res))
time.sleep(6)
在这个程序中,我们把要执行的相关任务,包含GPU矩阵的转化与分配,都放到了一个函数中,然后通过multiprocessing开启一个子进程,来执行这个任务,并且在任务中甚至不需要手动执行del这个删除的操作。这么一来,我们既可以实现对象的即时销毁,也通过进程控制的机制确保在显存中占用的位置被清空。如果进程执行中存在一些问题,还可以通过terminate的操作来直接杀死进程,同样也可以确保显存占用不会发生堆积的情况。程序的执行结果如下:
Array b has been deleted!
Is jax array deleted successfully? [True]
在程序执行的过程中我们也可以看到,在nvidia-smi中的显存占用,仅仅持续了2秒,也就是我们在函数内部设置的进程sleep参数。而在之后6秒的sleep时间中,这一块内存占用是被清空了的,这也就达到了我们最初的目的。当然,最重要的是,我们依然可以从函数中获取到返回值,这就确保后面有需要存储或者使用到的参数不被同步的销毁。需要注意的是,在同等条件下,如果不使用子进程来执行这个函数,而是直接使用res=f(a)的形式来执行,作为临时变量的b最终依然存在于显存之中,这是一个非常可怕的事情。
4.总结概要
在使用一些python
的GPU模块,或者写CUDA时,有时会发现显存被无端占用的场景,即时执行了cudaFree()或者python的del操作,也无法消除这一块的显存占用。最终我们发现,可以通过额外开启一个子进程的方法来封装相关的操作,通过对进程的存活控制来实现对GPU显存占用的控制,有可能是一个临时规避问题的思路。
来源:https://www.cnblogs.com/dechinphy/p/gc.html
猜你喜欢
- jsp登陆验证,网页登陆验证带验证码校验,登录功能之添加验证码part_1:专门用于生成一个验证码图片的类:VerificationCode
- 如何用Cookie进行登录验证?很简单,看看这两个文件:login.htm请注册登录随风起舞<FORM ACTION=&qu
- 就算我们每天在叫嚷着创新经济,设计救国,我们在生活中也无处不在的看到各种设计庸俗、制作粗劣的海报、店面、户外广告、大胸美女和肌肉 * 交相辉映
- 在我们建立一个数据库时,并且想将分散在各处的不同类型的数据库分类汇总在这个新建的数据库中时,尤其是在进行数据检验、净化和转换时,将会面临很大
- 如何编写具有良好结构的CSS?如果在设计流程中缺乏"秩序"或"章法"是非常不利的,你得冒着风险去添加
- 本文实例讲述了PHP判断是否微信访问的方法。分享给大家供大家参考,具体如下:在开发中有时需要禁止或者仅允许微信浏览器进行访问,则此时就需要对
- 获取指定日期月份的第一天,你可以使用DATEADD函数,减去指定日期的月份过去了的天数,即可。 代码如下:CREATE FUNC
- 看下面的一组例子:alert(true.toString());alert(false.toString());alert(1.123.to
- 这个类可以用来搜索在给定的文本目录中的文件。 它可以给定目录遍历递归查找某些文件扩展名的文件。 并打开找到的文件,并检查他们是否包含搜索词语
- 从而达到方便快捷的目的,但是它在存储信息的时候往往会有一些敏感的东西,这些东西可能成为被攻击的目标,如银行的账号、信用卡事务或档案记录等。这
- 姓名的翻译: 英语是名(First name)在前,姓(Last name)在后。中文地址的翻译:如果你英语水平不高,填表时只要国家名用英语
- http://swik.net/Ajax/Ajax+Mistakes在某网站瞎逛时,发现这个链接,进去逛了逛,觉得很有意思,大家也可以去看看
- parse_dates : boolean or list of ints or names or list of lists or dic
- 客户端: <%@ Page Language="C#" AutoEventWireup="true&qu
- 微软上周发布了一份关于 Windows Internet Explorer 8 浏览器(以下简称为 IE 8)性能优化的白皮书《Window
- 这个弹出层的登录界面挺好看,很清爽所以转了过来给大家分享,要实现这个功能很简单:首先设计一个登录界面,使用css中的display=&quo
- MongoDB已经使用很长一段时间了,基于MongoDB的数据存储也一直没有使用到权限访问(MongoDB默认设置为无权限访问限制),今天特
- 在Windows系统中用“Ctrl+C”和“Ctrl+V”就可以完成复制、粘贴工作,是不是很爽?其实使用a标签的accesskey属性也可以
- 网站开发时经常需要在某个页面需要实现对大量图片的浏览,如果考虑流量的话,大可以像pconline一样每个页面只显示一张图片,让用户每看一张图
- 本文实例讲述了Python列表list操作符。分享给大家供大家参考,具体如下:#coding=utf8''''