【问题标题】:How is CUDA memory managed?CUDA 内存是如何管理的?
【发布时间】:2012-01-30 20:52:15
【问题描述】:

当我运行仅分配少量全局内存(低于 20 M)的 CUDA 程序时,出现“内存不足”错误。 (从其他人的帖子中,我认为问题与内存碎片有关)我试图理解这个问题,并意识到我有几个与 CUDA 内存管理相关的问题。

  1. CUDA 中有虚拟内存的概念吗?

  2. 如果只允许一个内核同时在 CUDA 上运行,在其终止后,它使用或分配的所有内存是否都会释放?如果没有,这些内存何时释放?

  3. 如果允许在 CUDA 上运行多个内核,它们如何确保它们使用的内存不重叠?

谁能帮我回答这些问题?谢谢

编辑1:操作系统:x86_64 GNU/Linux CUDA 版本:4.0 设备:Geforce 200,它是机器附带的GPU之一,我认为它不是显示设备。

编辑2:以下是我做了一些研究后得到的。请随时纠正我。

  1. CUDA 将为每个主机线程创建一个上下文。此上下文将保留诸如已为该应用程序保留的内存部分(预分配的内存或动态分配的内存)等信息,以便其他应用程序无法写入。当这个应用程序(不是内核)终止时,这部分内存将被释放。

  2. CUDA 内存由链接列表维护。当应用程序需要分配内存时,它会通过这个链表查看是否有连续的内存块可供分配。如果找不到这样的块,即使总可用内存大小大于请求的内存,也会向用户报告“内存不足”错误。这就是与内存碎片有关的问题。

  3. cuMemGetInfo 会告诉您有多少内存可用,但不一定会告诉您由于内存碎片,您可以在最大分配中分配多少内存。

  4. 在 Vista 平台 (WDDM) 上,GPU 内存虚拟化是可能的。也就是说,多个应用程序可以分配几乎整个 GPU 内存,而 WDDM 将管理将数据交换回主内存。

新问题: 1. 如果上下文中保留的内存在应用程序终止后会被完全释放,则不应该存在内存碎片。内存中一定还有一些数据。 2. 有没有办法重构GPU内存?

【问题讨论】:

  • 您能否编辑问题以包括您使用的操作系统、GPU 和 cuda 版本,以及 GPU 是显示设备还是非显示设备。这将影响您问题的正确答案。
  • 回答额外的问题 - 用户可观察到的碎片发生在上下文中,并且无法更改 GPU 内的内存映射,这一切都由主机处理司机。
  • 正如您所解释的,上下文分配由上下文静态分配、上下文用户分配和CUDA上下文运行时堆组成。我认为上下文静态分配和上下文用户分配的大小是预先确定的。因此,我认为内存碎片的唯一原因是上下文运行时堆,它只在 Fermi 架构上。那是对的吗?我猜系统会为上下文运行时堆预先分配一块内存,以便启用内核内动态内存分配。
  • 您的问题目前有点混乱。你能把它编辑成只有初始背景,然后是一堆问题吗?

标签: cuda nvidia gpu


【解决方案1】:

您的代码在运行时可用的设备内存基本上计算为

Free memory =   total memory 
              - display driver reservations 
              - CUDA driver reservations
              - CUDA context static allocations (local memory, constant memory, device code)
              - CUDA context runtime heap (in kernel allocations, recursive call stack, printf buffer, only on Fermi and newer GPUs)
              - CUDA context user allocations (global memory, textures)

如果您收到内存不足消息,那么在您的用户代码尝试在 GPU 中获取内存之前,前三项中的一项或多项可能正在消耗大部分 GPU 内存。如果,如您所指出的,您没有在显示 GPU 上运行,那么上下文静态分配最有可能是您的问题的根源。 CUDA 通过在设备上建立上下文时预先分配上下文所需的所有内存来工作。有很多东西被分配来支持上下文,但上下文中最大的消费者是本地内存。对于设备上的每个多进程,运行时必须为每个多处理器可以同时运行的最大线程数保留上下文中的任何内核将消耗的最大本地内存量。如果在具有大量多处理器的设备上加载本地内存繁重的内核,这可能会占用数百 Mb 的内存。

查看可能发生的情况的最佳方法是编写一个没有设备代码的主机程序,该程序建立一个上下文并调用cudaMemGetInfo。这将向您显示设备具有多少内存,并且其上的上下文开销最小。然后运行有问题的代码,在第一个 cudaMalloc 调用之前添加相同的 cudaMemGetInfo 调用,这将为您提供上下文正在使用的内存量。这可能让您了解内存的去向。如果您在第一次 cudaMalloc 调用时失败,那么碎片不太可能成为问题。

【讨论】:

  • talonmies,感谢您的信息。这是非常有帮助的。还有一个问题,设备内存中是否可能存在多个上下文?
  • 是的,这是可能的,但是给定的线程只能在给定的设备上保存一个上下文。通常的情况是两个进程试图同时在同一个 GPU 上运行,或者一个多线程应用程序打开两个具有两个线程的上下文。后者在 CUDA 4 中比以前更难做到。
  • 那么使用什么机制来为多个上下文分配内存呢?系统如何确保为不同的上下文分配不同的内存部分?
  • 使用cudaMalloc分配的内存属于“CUDA上下文静态分配”,对吗?
  • 否,上下文用户分配。静态分配是那些编译到上下文中的东西(本地内存、常量内存、静态符号、设备代码)。不同的上下文由 CUDA 主机驱动程序(和 vista/win7 上的 WDDM)管理。每个 CUDA 上下文都有自己的虚拟地址空间,并且驱动程序保持分离。内存和指针在上下文之间是不可移植的(使用 Fermi 唯一统一地址空间模型时除外)。您必须相信驱动器可以正常工作(并且确实可以......)
【解决方案2】:
  1. GPU 片外内存分为全局内存、本地内存和常量内存。这三种内存类型是一个虚拟内存概念。全局内存对所有线程都是免费的,本地仅适用于一个线程(主要用于寄存器溢出),常量内存是缓存的全局内存(只能从主机代码写入)。查看 CUDA C 编程指南中的 5.3.2。

  2. 编辑:删除

  3. 通过cudaMalloc 分配的内存永远不会重叠。对于内核在运行时分配的内存应该有足够的可用内存。如果您内存不足并尝试启动内核(只是我的猜测),您应该会收到“未知错误”错误消息。驱动程序无法启动和/或执行内核。

【讨论】:

  • 感谢您的回复。但我想我想要更底层的解释。我从其他帖子中了解到,CUDA 内存管理需要处理上下文和一些数据结构,但我需要更多详细的解释,以便找出程序中的内存问题。
  • 您的第二个答案大多是错误的。内核范围内存在设备上建立上下文时预分配。本地内存的内容仅在内核运行期间有效,但在建立上下文时会保留内存本身。动态内存是从运行时堆分配的,该堆也在上下文建立时保留,并且在上下文的生命周期内保持可访问和有效,而不是内核。如果需要,有一个 API 调用用于在运行时根据默认大小操作堆大小。
猜你喜欢
  • 2010-12-13
  • 2018-07-12
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-30
相关资源
最近更新 更多