当前位置: 首页 > 面试题库 >

无需过度使用linux上的Malloc

曾航
2023-03-14
问题内容

如何在Linux上分配内存而又不过度使用内存,以便NULL在没有可用内存并且进程不会在访问时随机崩溃的情况下,malloc实际上返回?

我对malloc如何工作的理解:

  1. 分配器检查空闲列表是否有可用内存。如果是,则分配内存。
  2. 如果否,则从内核分配新页面。这就是过度使用可能发生的地方。然后返回新的内存。

因此,如果有一种方法可以从立即由物理内存支持的内核中获取内存,则分配器可以使用该内存而不是获取过量使用的页面,NULL如果内核拒绝提供更多的内存,则分配器可以返回。

有办法吗?

更新:

我知道这不能完全保护该过程免受OOM杀手的侵害,因为如果它的得分很差,它仍然会在内存不足的情况下被杀死,但这不是我担心的。

更新2: 名义动物的评论给了我以下使用的想法mlock

void *malloc_without_overcommit(size_t size) {
    void *pointer = malloc(size);
    if (pointer == NULL) {
        return NULL;
    }
    if (mlock(pointer, size) != 0) {
        free(pointer);
        return NULL;
    }

    return pointer;
}

但这可能由于所有系统调用而相当慢,因此,这应该在分配器实现的级别上完成。而且它还会阻止使用交换。

更新3:

根据约翰·博林格斯(John Bollingers)的评论提出了新想法:

  1. 检查是否有足够的内存。据我了解,这必须/proc/meminfoMemFreeSwapFree值中进行检查。
  2. 仅当有足够的可用空间(加上额外的安全裕度)时,才分配内存。
  3. 找出pagesize,getpagesize并在每个pagesize中向内存写入一个字节,以便它得到物理内存(RAM或swap)的支持。

我还仔细查看了mmap(2),发现了以下内容:

MAP_NORESERVE

不要为该映射保留交换空间。当保留交换空间时,可以保证可以修改映射。如果没有保留交换空间,则在没有物理内存可用的情况下,可能会在写入时获得SIGSEGV。另请参阅proc(5)中有关文件/
proc / sys / vm / overcommit_memory的讨论。在2.6之前的内核中,此标志仅对私有可写有效

这是否意味着进行映射~MAP_NORESERVE将完全保护该过程免受OOM杀手的侵害?如果是这样,这是一个完美的解决方案,只要有malloc实现,它就可以直接在之上工作mmap。(也许是jemalloc?)

更新4: 我目前的理解是,~MAP_NORESERVE这不能防止OOM杀手,但至少可以防止在首次写入内存时出现段错误。


问题答案:

如何在Linux上分配内存而不过度使用

那是一个加载的问题,或者至少是一个不正确的问题。该问题基于错误的假设,这使得回答所陈述的问题充其量是不相关的,最糟糕的是会引起误解。

内存过量使用是一项系统范围的策略-
因为它确定为进程提供了多少虚拟内存-而不是由进程自己决定的事情。

由系统管理员确定内存是否过量使用。在Linux中,该策略是相当可调整的(例如/proc/sys/vm/overcommit_memory,参见man
5 proc中的内容

在分配期间,没有任何进程会影响内存过量使用策略

OP也似乎对使自己的进程不受Linux中的内存不足杀手(OOM杀手)的影响很感兴趣。(Linux中的OOM杀手是一种通过杀死进程,从而将其资源释放回系统来减轻内存压力的技术。)

这也是不正确的方法,因为OOM杀手是一个启发式过程,其目的不是“惩罚或杀死行为不良的过程”,而是使系统保持运行状态。此功能在Linux中也很可调,而且系统管理员甚至可以调整在内存压力大的情况下每个进程被杀死的可能性。除了进程使用的内存量以外,
还不完全取决于该进程来影响OOM杀手在内存不足的情况下是否将其杀死 。这也是系统管理员管理的策略问题,而不是流程本身。

我认为OP试图解决的实际问题是如何编写可以动态响应内存压力而不只是死掉的Linux应用程序或服务(由于SIGSEGV或OOM杀手的原因)。答案是 您不会
-让系统管理员担心对他们来说重要的事情,而不是他们的工作量-
除非您的应用程序或服务是使用大量内存的应用程序或服务因此在高内存压力下可能会被不公平地杀死。(特别是如果数据集足够大以至于需要进行比原先启用的交换量大得多的交换,则会导致较高的交换风暴风险,并且后期OOM杀手会太强。)

解决方案,或者至少是可行的方法,是对关键部分(甚至是整个应用程序/服务,如果它适用于不应交换到磁盘的敏感数据)进行内存锁定,或者将内存映射用于专用的备份文件。(对于后者,这是我在2011年编写的示例,该示例操作了TB级的数据集。)

OOM杀手仍然可以终止进程,并且仍然会发生SIGSEGV(由于内核无法向其提供RAM支持的库函数内部分配),除非所有应用程序都被锁定到RAM,但至少服务/流程不再是不
公平的 目标,只是因为它使用了大量内存。

可能会捕获到SIGSEGV信号(在没有可用内存来备份虚拟内存时发生),但是到目前为止,我还没有看到可以保证代码复杂性和所需维护工作的用例。

总之,对所述问题的正确答案是“ 否”,不要这样做



 类似资料:
  • 我在linux(ubuntu 12.04)上通过python使用openCV,我有一个罗技c920,我想从中抓取图像。Cheese能够抓取非常高分辨率的帧,但是每当我尝试使用openCV时,我只得到640x480的图像。我曾经尝试过: 但这会在最后两行中的每一行之后产生“0”的输出,当我随后通过以下方式获取帧时: 生成的图像仍然是640x480。 我曾尝试通过(python之外的)安装似乎相关的工

  • 问题内容: 嗨,我正在使用ganymed-ssh2 Java库在Linux工作站中成功执行远程命令。 但是现在有一种情况,我需要执行命令,但这需要我输入一些密码…,例如: 我曾经以这种方式实现远程cmd执行: 恐怕无法使用此库执行需要密码的命令。 有人可以给我解决方案或替代方案,以允许这样做? 谢谢! 问题答案: 假设有一个,您应该能够将密码输入sudo命令。

  • 问题内容: 我在应用程序中使用selenium-server,selenium rc进行UI测试。我的开发箱是带有FireFox 3.5的Windows,一切运行正常。但是当我尝试在我的构建服务器(是linux机器)上运行selenium测试时,出现此错误 基本上,selenium-rc无法在Linux(实际上是.sh文件)上找到Firefox可执行文件,在Windows中是存在的。 有人遇到过这

  • 无法在linux上使用ElasticSearch映射logstash 我只是运行下面的命令,它显示了docker上所有正在运行的图像 sudo docker ps 输出: 我只想将logstash链接到弹性搜索并尝试运行以下命令 命令: 输出: 989e2a8f4d9fd972c4f2102d726a68877c989b546800899abbb8c382fb62f04c logstash。形态:

  • 问题内容: 我有一个grails应用程序,它依赖于服务中的同步块。当我在Windows上运行它时,同步可以按预期工作,但是当我在ams linux上运行时,会收到StaleObjectStateException。 在下面的示例中重现该问题。 } 据我了解,发生此异常是因为多个线程正在尝试保存同一对象。这就是为什么我使用同步块。 Linux Java: Java版本“ 1.7.0_85” Open

  • 问题内容: 我正在用Java创建一个应用程序,对于该应用程序我只希望运行一个实例。为此,我创建了一个文件,并在我的应用程序运行时锁定了它。 我有以下代码可在Windows上运行,但在Linux上无法运行:一旦我获得了一个锁而没有将其解锁,则可以再获得一个锁。 问题答案: 我使用了与您相同的示例,并且在Mac OS X上遇到了同样的问题。似乎文件锁定不能防止在POSIX系统上删除文件。在解锁之前,您