【问题标题】:Is there a known issue with memory leaks in Python dicts or Numpy iterators?Python dicts 或 Numpy 迭代器中的内存泄漏是否存在已知问题?
【发布时间】:2019-06-21 14:29:48
【问题描述】:

使用 nd.iter 迭代大型 Numpy 数组的函数消耗的内存比预期的要多。

我有一个包含类值的大 (~120mb) 图像(每个 uint8 介于 0 和 9 之间)。对于每个类,我想建立一个可用于进一步操作的指标列表,如下所示:

class_dict = {
    1:[(2,3),(2,4),(2,5).....],   # Pixels containing class 1
    2:[(30000,2333),(54444,23232) .....],    # Pixels containing class 2
    ....
}

目前这是由以下代码产生的:

class = gdal.Open("path/to/class/geotiff")
class_array = gdal.GetVirtualMemArray()  # shape=(11027,10954)

def build_class_dict(class_array, no_data=None):
    """Returns a dict of coordinates of the following shape:
    [class, coord_list]"""
    out_dict = {}
    it = np.nditer(class_array, flags=['multi_index'])
    while not it.finished:
        this_class = int(it.value)
        if this_class == no_data:
            it.iternext()
            continue
        if this_class in out_dict.keys():
            out_dict[this_class].append(it.multi_index)
        else:
            out_dict.update({this_class: [it.multi_index]})
        it.iternext()
    return out_dict

鉴于我基本上将整个图像再次存储了两次,我预计该函数的内存占用量会增长相当多 - 比如说大约 3gb,考虑到通常的 Python 开销,这不是问题。

正在发生的事情是程序的占用空间增长得非常快,以填满所有可用空间。对于具有大量(约 80%)nodata 值的图像,它会在大约一分钟内完成,但对于其他任何东西,它都会使机器资源匮乏并锁定。

这个实现是否存在内存方面的问题,还是我必须重新考虑?环境是 Python 3.6.7,numpy 1.15.4(但在 1.16.4 上试过),gdal 2.4.1,在 ubuntu 18.02 上运行。

编辑 进一步的发展;当使用 @memory_profiler.profile 装饰器分析函数时,内存会跳跃然后保持稳定——这是我所期望的。这不是它在不受监控时的行为方式,但它的运行速度也慢得多。

【问题讨论】:

    标签: python numpy memory-leaks gdal


    【解决方案1】:

    所以源数组是形状(11027,10954)uint8 dtype。它的内存使用量大约为 120789758 字节 - 每个像素一个字节。

    暂时忽略nodata,字典包含相同数量的元组,每个元组有两个整数(每个 4 或 8 个字节),分为 10 个列表。那是 3*120789758 指针。更高的内存使用率。这不是泄漏,只是需要大量内存的数据结构。

    我通常不鼓励在 Python 代码中使用 nditer,因为它与普通迭代相比没有任何速度优势。但是由于您将它用于多索引,因此它可能不是一个糟糕的选择。

    你的字典用法看起来很像collections.defaultdict。这可能会缩短您的代码,但不会改变内存使用或速度。

    如果 nodata 为 0,您也可以将此图像放在 scipy.sparse.dok_matrix 中 - 除了字典键是索引元组本身,字典值是像素值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多