草庐IT

共享内存简介及docker容器的shm设置与修改

Adenialzz 2023-04-22 原文

共享内存简介及docker容器的shm设置与修改

共享内存简介

共享内存指 (shared memory)在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache)。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同的处理器可能用到不同的数据。共享内存是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。

实际上,共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。

docker容器shm的设置与修改

问题

我们在 docker 容器来跑我们的 PyTorch 模型训练任务时如果设置不当,会遇到类似这样的报错:

RuntimeError: DataLoader worker (pid 1229) is killed by signal: Bus error. 
It is possible that dataloader's workers are out of shared memory. 
Please try to raise your shared memory limit.

可以看到,这是 DataLoader 的保存,我们在设置 DataLoader 时通常会给一个 num_workers 的值(该值推荐设置为本机的 CPU 核心数),但是在 docker 容器中训练任务时,或许我们的宿主机有很大内存空闲,但是却会报上面的共享内存不足的问题。

这就是由于我们在创建 docker 容器时没有给足够的共享内存(默认为 64MB)。共享内存的大小我们可以在容器内通过以下命令查看:

df -lh | grep shm
# 输出:
shm              64M     0   64M   0% /dev/shm

或者:

ipcs -al
# 输出:
------ Messages Limits --------
max queues system wide = 32000
max size of message (bytes) = 8192
default max size of queue (bytes) = 16384

------ Shared Memory Limits --------
max number of segments = 4096
max seg size (kbytes) = 18014398509465599
max total shared memory (kbytes) = 18014398509481980
min seg size (bytes) = 1

------ Semaphore Limits --------
max number of arrays = 32000
max semaphores per array = 32000
max semaphores system wide = 1024000000
max ops per semop call = 500
semaphore max value = 32767

这种情况有三种解决方法。

解决方法

方法一

方法一就是直接不要设置 num_workers 了,让它为默认值 0,这时就不需要很大的共享内存了,任务可以正常跑起来。

该方法的问题是:我们跑训练任务时肯定是需要很大的 num_workers 的,不然数据运输太慢会导致 GPU 利用率很低。

因此该方法仅适用于我们在容器内 debug 训练代码时,此时不需要很大的 num_workers,只要保证代码无误,然后在正式开始跑训练时正常设置共享内存和 num_workers 即可。

方法二

那么,应该怎样正确设置共享内存的大小呢?其实很简单,只需要我们在启动容器时加一个参数 --shm-size 即可,如:

docker run -it \
        --gpus '"device=0,1"' \
        --shm-size 32g \
        --mount type=bind,source=/ssd1t/song/Datasets/coco,target=/master_data \
        adenialzz/bilibili-projects:tch-mmdet-py38-tch19

即可将共享内存设置为 32g。

但是,有时我们在容器内已经做了一些事情,不想新建容器,而就是想改变当前容器的共享内存该怎么办呢?

方法三

这种情况稍微麻烦一点,但也是可以实现的,步骤如下:

  1. 首先关闭 docker 服务:

    service docker stop
    
  2. 查看当前容器的 id:

    docker ps -a
    

    找到我们要修改的容器的 CONTAINER ID,就是第一列,长得像这样:685d249a0965 的一个序列,通常显示的是简短的版本(即完整 ID 的开头几个字符),实际这个 ID 很长。

  3. 找到该容器配置文件所在目录

    cd /var/lib/docker/containers
    ls
    cd 685d249a096569335605747977dcb3d705947b1049259de2e259dc4b9a7da3fa
    

    这时会显示出几个以当前存在的容器 ID 为名的目录,找到我们要修改共享内存的那个(开头匹配我们刚才记下的 CONTAINER ID),进入目录。

  4. 修改宿主机中的 host 配置文件(此步通常需要 root 权限)

    vim hostconfig.json
    

    然后会看到一堆东西,找到 "ShmSize":67108864,可以看到,现在就是 67108864 字节,即64MB,我们就是要修改该值,比如在后面填俩零就是扩大了一百倍,自己算一下需要的共享内存大小,按需扩大,保存退出。

  5. 重启 docker 服务

    // 停止docker服务
    systemctl stop docker  
    // 再开启
    systemctl start docker  
    
    //或者
    systemctl restatrt docker
    
    //或者
    service docker stop
    service docker start
    
  6. 再打开容器,进去看一下吧

Ref:

https://blog.csdn.net/gg864461719/article/details/112466585

有关共享内存简介及docker容器的shm设置与修改的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  3. ruby-openid:执行发现时未设置@socket - 2

    我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

  4. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  5. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  6. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

    我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

  7. ruby-on-rails - Ruby 中的内存模型 - 2

    ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序

  8. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  9. ruby-on-rails - 有没有办法为 CarrierWave/Fog 设置上传进度指示器? - 2

    我在Rails应用程序中使用CarrierWave/Fog将视频上传到AmazonS3。有没有办法判断上传的进度,让我可以显示上传进度如何? 最佳答案 CarrierWave和Fog本身没有这种功能;你需要一个前端uploader来显示进度。当我不得不解决这个问题时,我使用了jQueryfileupload因为我的堆栈中已经有jQuery。甚至还有apostonCarrierWaveintegration因此您只需按照那里的说明操作即可获得适用于您的应用的进度条。 关于ruby-on-r

  10. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

随机推荐