在Linux驱动程序编程中,devm_kzalloc()和kzalloc()有什么区别?

22

我在设备驱动程序中发现了devm_kzalloc()kzalloc(),但我不知道何时/在哪里使用这些函数。请问有人能够说明这些函数的重要性和用法吗?


1
嗨,如果我们使用devm_kzalloc(),那么无需释放此内存(参考:链接)。因此,我们是否可以在程序中将所有的kzalloc()函数替换为devm_kzalloc(),以减轻动态分配内存时的负担..? - Raj
我相信devres.txt可以回答大部分问题。'devres.txt'应该适用于您的Linux版本(从2.6.31+)。 - artless noise
不可以将所有的分配都替换为托管类似物,因为必须仔细考虑对象的生命周期。 - 0andriy
2个回答

50

kzalloc() 分配内核内存,类似于kmalloc(),但它也将分配的内存置零。 devm_kzalloc()是管理kzalloc()的函数。使用管理函数分配的内存与设备相关联。当设备从系统中分离或设备的驱动程序卸载时,该内存会自动释放。如果为设备分配了多个管理资源(内存或其他资源),则最后分配的资源最先释放。

管理资源对于确保驱动程序在任何点初始化失败和成功初始化后设备移除的正确操作非常有帮助。

请注意,管理资源(无论是内存还是其他资源)应用于负责探测设备的代码中。通常不应用于用于打开设备的代码,因为设备可以在未断开连接的情况下关闭。关闭设备需要手动释放资源,这违反了管理资源的目的。

使用kzalloc()分配的内存应通过kfree()释放。使用devm_kzalloc()分配的内存会自动释放。虽然可以使用devm_kfree()释放此内存,但这通常意味着管理内存分配不适合当前任务。


2
值得一提的是,托管资源的使用案例是 ->probe() 或类似的回调函数。在像 ->open() 这样的回调函数中使用它们是一个非常糟糕的想法。此外,在文件操作中存在对象生命周期的问题。 - 0andriy
我已经扩展了我的回复并提到了它,谢谢。如果有其他避免在open()中使用托管资源的原因,请发布链接。 - proski

2
简单来说,devm_kzalloc()和kzalloc()都用于设备驱动程序中的内存分配,但区别在于如果您使用kzalloc()分配内存,则必须在该设备驱动程序的生命周期结束或从内核卸载时释放该内存,但如果您使用devm_kzalloc()进行相同操作,则无需担心释放内存,该内存会自动由设备库释放。
它们都执行完全相同的操作,但通过使用devm_kzalloc,程序员可以减少一些释放内存的开销。
让我们通过一个例子来解释,第一个例子是使用kzalloc。
static int pxa3xx_u2d_probe(struct platform_device *pdev)
{
    int err;
    u2d = kzalloc(sizeof(struct pxa3xx_u2d_ulpi), GFP_KERNEL);     1
    if (!u2d)
         return -ENOMEM;
    u2d->clk = clk_get(&pdev->dev, NULL);
    if (IS_ERR(u2d->clk)) {
        err = PTR_ERR(u2d->clk);                                    2
        goto err_free_mem;
    }
...
    return 0;
err_free_mem:
    kfree(u2d);
    return err;
}
static int pxa3xx_u2d_remove(struct platform_device *pdev)
{
    clk_put(u2d->clk);               
    kfree(u2d);                                                     3
    return 0;
}

在这个例子中,您可以在函数pxa3xx_u2d_remove()中看到,kfree(u2d)(标记为3的行)用于释放由u2d分配的内存。现在通过使用devm_kzalloc()来看同样的代码。

static int pxa3xx_u2d_probe(struct platform_device *pdev)
{
    int err;
    u2d = devm_kzalloc(&pdev->dev, sizeof(struct pxa3xx_u2d_ulpi), GFP_KERNEL);
    if (!u2d)
        return -ENOMEM;
    u2d->clk = clk_get(&pdev->dev, NULL);
    if (IS_ERR(u2d->clk)) {
         err = PTR_ERR(u2d->clk);
         goto err_free_mem;
    }
...
    return 0;
err_free_mem:
    return err;
}
static int pxa3xx_u2d_remove(struct platform_device *pdev)
{
    clk_put(u2d->clk);
    return 0;
}

由于devm_kzalloc()函数已经完成了与kfree()相同的操作,因此不需要使用kfree()函数来释放内存。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接