【问题标题】:GLib handle out of memoryGLib 句柄内存不足
【发布时间】:2013-06-07 00:10:31
【问题描述】:

我有一个关于 GLib 的问题。 我想在服务器上下文中使用 GLib,但我不知道如何管理内存: https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html

如果任何分配内存的调用失败,应用程序将终止。这也意味着无需检查调用是否成功。

如果我看源码,如果g_malloc失败了,就会调用g_error:

g_error()

定义 g_error(...)

记录错误消息的便捷函数/宏。 错误消息总是致命的,导致调用 abort() 来终止应用程序。[...]

但在我的情况下,当我正在开发一个服务器应用程序时,我不希望应用程序退出,我更喜欢作为传统的 malloc 函数,GLib 函数返回 NULL 或指示发生错误的东西。

所以,我的问题是,有办法处理内存不足吗? 是否不建议将 GLib 用于服务器用途的应用程序?

如果我看看 man of abort,我会发现我可以处理信号,但我会让内存不足错误的管理有点痛苦......

abort() 函数会导致程序异常终止,除非 信号 SIGABRT 被捕获并且信号处理程序没有 返回。

感谢您的帮助!

【问题讨论】:

标签: c memory glib


【解决方案1】:

从内存不足中恢复是非常困难的。原因是它可以被认为是一种终端状态,因为缺乏记忆会在它消失之前持续一段时间。即使是对内存不足的反应(比如通知用户)也可能需要更多的内存,例如,构建和发送消息。一个相关的问题是,有些操作系统(至少是 Linux)可能对分配内存过于乐观。当内核意识到内存丢失时,它可能会终止应用程序,即使您的代码正在处理故障。

因此,要么您对整个系统的掌握比一般人更严格,要么您将无法成功处理内存不足错误,在这种情况下,帮助程序库在做什么并不重要.

如果你真的想在仍然使用 glib 的同时控制内存分配,你有部分方法可以做到这一点。不要使用任何 glib 分配函数并使用其他库中的一些。 Glib 提供了在必要时接收“免费函数”的函数。例如:

https://developer.gnome.org/glib/2.31/glib-Hash-Tables.html#g-hash-table-new-full

哈希表构造函数接受用于销毁键和值的函数。在您的情况下,数据将使用自定义分配函数进行分配,而哈希数据结构将使用 glib 函数进行分配。

您也可以使用 g_try_* 宏来分配内存,因此您仍然使用 glib 分配器,但它不会因错误而中止。同样,这只能部分解决问题。在内部,glib 会隐式调用可能会中止的函数,并假定它永远不会在出错时返回。

关于一般问题:服务器在内存不足时崩溃是否有意义?显而易见的答案是否定的,但我无法估计这个答案的理论性。我只能期望服务器系统的大小适合其操作,并拒绝任何可能超出其容量的输入无效,为此,它可能使用哪些库并不重要。

【讨论】:

  • 感谢您的回答 hdante,我投了赞成票。我知道内存不足可能是应用程序的终端状态,但在我的情况下,解决方案非常简单,关闭遇到问题的客户端并释放其资源。它应该释放一些内存,其他客户端可能能够继续运行。我不知道 Linux 可以在不求和的情况下杀死您的应用程序,这很奇怪。在服务器的核心(关于套接字管理的一切)中,我严格掌握了内存管理。我想使用一个库作为 GLib 来加速“业务”部分的开发。
  • 我不同意很难从内存不足中恢复。让事情变得困难的是默认过度使用的 Linux 模型。如果您认为 malloc 可以返回 null 并将其应用于整个代码库,那是非常可行的。使用过这样的代码库后,我并没有发现它具有挑战性,而且在实践中(如现场所见),您大部分时间都可以从中恢复(甚至以一种向用户展示的方式)。忽视问题是一种逃避。
【解决方案2】:

我可能在这里进行了一些编辑,但是现代使用虚拟/逻辑内存的趋势(这两个名称都已使用,尽管“逻辑”更明显)确实使知道内存何时耗尽变得非常复杂,尽管我认为一个可以使用/etc/sysctl.d/10-no-overcommit.conf 中的以下内容在 Linux 中恢复旧的、真实的(RAM + 交换)模型(我称之为物理模型):

vm.overcommit_memory = 2
vm.overcommit_ratio = 100

这恢复了这样一种理念,即如果程序的malloc 刚刚失败,则该程序很有可能是内存耗尽的实际原因,然后可以退出当前对象的构造, freeing 一路上的内存,可能会抱怨用户要求一些需要太多 RAM 的疯狂的东西,并等待下一个请求。在此模型中,大多数 OOM 条件几乎立即解决 - 程序要么应对并可能返回 RAM,要么在尝试使用 malloc 返回的 0 时在下一个 SEGV 上立即终止。

使用 linux 在 2013 年默认使用的虚拟/逻辑内存模型,这是行不通的,因为程序找不到内存在 malloc 不可用,而是在稍后尝试访问内存时此时内核终于意识到 RAM 中没有它的位置。这相当于一场灾难,因为系统上的任何程序都可能死掉,而不是主机内存不足的那个。我们可以理解为什么有些 GLib 的人甚至不关心尝试解决这个问题,因为使用逻辑内存模型,它无法被修复。

逻辑内存的初衷是允许使用主机一半以上内存的大型程序仍然能够 fork 和 exec 支持程序。它通常仅在具有该特定使用模式的主机上启用。现在在 2013 年,当家庭工作站可以拥有 24+ GiB 的 RAM 时,真的没有任何借口可以在 99% 的时间内启用逻辑内存。默认情况下,它应该在启动时具有 >4 GiB RAM 的主机上被禁用。

无论如何。因此,如果您想采用老式物理模型方法,请确保您的计算机已启用它,否则测试您的 mallocrealloc 调用毫无意义。

如果您在该模型中,请记住 GLib 并没有真正遵循相同的理念(请参阅 http://code.google.com/p/chromium/issues/detail?id=51286#c27 了解其中一些人是多么疯狂地误入歧途)。任何基于 GLib 的库可能也会被同样的态度感染。但是,通过使用g_mem_set_vtable() 放置您自己的内存处理程序,您可以在物理内存模型中使用 GLib 做一些有趣的事情,因为您可能能够在程序全局变量中四处寻找并减少缓存等中的使用释放空间,然后重试底层malloc。但是,由于在调用您的特殊处理程序时不知道正在构建哪个对象,这有其自身的限制。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-09
    • 2014-10-15
    • 2020-12-20
    • 2015-05-22
    • 2013-05-18
    • 2011-05-21
    • 1970-01-01
    • 2010-12-26
    相关资源
    最近更新 更多