当我分配大量的ndarray时,numpy空做什么?

Ero*_*mic 2 c python memory-management numpy linux-kernel

我看着内存中的numpy数组消耗了多少空间,并且发现了一个奇怪的行为:

我跑的时候 x = np.empty((1000000, 7, 64, 64), dtype=np.uint8)

我的16GB内存的计算机没有崩溃。相反,它分配了2GB内存时运行顺利。

此numpy阵列的重量应为26.70 GB,但似乎正在发生一些延迟。当我添加一个时,懒惰立即停止,我的程序挂起,并且它们得到一个MemoryError

我想知道引擎盖下是如何做的。

我看了一眼numpy.core.multiarray,发现numpy/core/src/multiarray/multiarraymodule.c下面这段代码似乎是空的定义:

static PyObject *
array_empty(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds)
{

    static char *kwlist[] = {"shape","dtype","order",NULL};
    PyArray_Descr *typecode = NULL;
    PyArray_Dims shape = {NULL, 0};
    NPY_ORDER order = NPY_CORDER;
    npy_bool is_f_order;
    PyArrayObject *ret = NULL;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&", kwlist,
                PyArray_IntpConverter, &shape,
                PyArray_DescrConverter, &typecode,
                PyArray_OrderConverter, &order)) {
        goto fail;
    }

    switch (order) {
        case NPY_CORDER:
            is_f_order = NPY_FALSE;
            break;
        case NPY_FORTRANORDER:
            is_f_order = NPY_TRUE;
            break;
        default:
            PyErr_SetString(PyExc_ValueError,
                            "only 'C' or 'F' order is permitted");
            goto fail;
    }

    ret = (PyArrayObject *)PyArray_Empty(shape.len, shape.ptr,
                                            typecode, is_f_order);

    PyDimMem_FREE(shape.ptr);
    return (PyObject *)ret;

 fail:
    Py_XDECREF(typecode);
    PyDimMem_FREE(shape.ptr);
    return NULL;
}
Run Code Online (Sandbox Code Playgroud)

我想知道如何在C语言中实现这种惰性,以及在numpy中将在其他地方弹出。

Bak*_*riu 5

注意,内核可以执行延迟分配。即malloc实际上并没有保留内存。第一次访问内存时,将发生页面错误,内核将执行实际分配(并可能决定只分配该页面的内存,而不分配整个数组)。

换句话说:C并不懒惰。延迟分配的是内核。

当您尝试向数组元素中添加一个数组时,会发生错误,因为该操作会修改所有内存位置,因此内核被迫实际上将所有数组放入内存中而失败。


我不是OS内存管理方面的专家,所以以上就是我所记得的OS课程。可以在这里找到一个参考。引用它:

另一方面,Linux严重损坏。默认情况下,它将对大多数内存请求回答“是”,以希望程序所要求的超出实际需求。

这就是说,即使所需的内存太大,内核也malloc几乎不会返回a NULL。它“希望”用户实际上不会使用他们请求的所有内存,这样他就可以避免加载某些页面并适合所需的数据。显然,这并不总是正确的。

  • +1,但我不会仅仅因为 Linux 内核允许过度使用虚拟内存而称其为“严重损坏”。如果内核只分配可以严格保证足够物理存储的虚拟内存,那么你最终会遇到同样荒谬的情况,即即使 80% 的 RAM 未使用,内核也会拒绝为新对象分配任何内存,简单地说因为,比如说,一些懒惰的开发人员决定“malloc”一个只需要 1GB 的 16GB 数组。 (2认同)