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

关于内存,Java Runtime.exec()从哪个Linux内核/ libc版本安全?

逑阳泽
2023-03-14
问题内容

在工作中,我们的目标平台之一是运行Linux的资源受限小型服务器(内核2.6.13,基于旧的Fedora
Core的自定义发行版)。该应用程序是用Java(Sun JDK 1.6_04)编写的。Linux
OOM杀手配置为在内存使用量超过160MB时杀死进程。即使在高负载下,我们的应用程序也永远不会超过120MB,并且与其他活动的本机进程一起,我们也始终保持在OOM限制内。

但是,事实证明,Java
Runtime.getRuntime()。exec()方法(一种从Java执行外部过程的规范方法)在Linux上具有一种特别不幸的实现,该实现导致生成的子进程(临时)需要相同数量的子进程。由于复制了地址空间,因此内存作为父进程。最终结果是,一旦执行Runtime.getRuntime()。exec(),我们的应用程序就会被OOM杀手杀死。

目前,我们通过一个单独的本机程序执行所有外部命令来解决此问题,并通过套接字与该程序进行通信。这不是最佳的。

在网上发布有关此问题的信息后,我得到了一些反馈,表明这不应在“较新”版本的Linux上发生,因为它们使用写时复制实现posix
fork()方法,大概意味着它将仅复制需要的页面。在需要时修改而不是立即修改整个地址空间。

我的问题是:

  • 这是真的?
  • 这是内核,libc实现还是其他地方的东西?
  • 从哪个版本的内核/ libc / fork()可以进行写时复制?

问题答案:

这是* nix(和linux)自从时间曙光(或mmus黎明)以来一直工作的方式。

要在*
nixes上创建新进程,请调用fork()。fork()使用其所有内存映射,文件描述符等创建调用过程的副本。内存映射是写时复制的,因此(在最佳情况下)实际上不会复制任何内存,而仅复制这些映射。接下来的exec()调用将当前的内存映射替换为新的可执行文件的映射。因此,fork()/
exec()是创建新进程的方式,而这正是JVM使用的方式。

需要注意的是,繁忙的系统上存在大量进程,父级可能会继续运行一会儿,然后子级exec()会导致大量内存被复制,从而导致写时复制。在VM中,内存可以移动很多,以方便垃圾收集器产生更多的副本。

“解决方法”是做您已经做的事情,创建一个外部轻量级进程来处理产生新进程的过程,或者使用比fork /
exec更轻量级的方法来产生进程(而linux没有,并且无论如何都会这样做)需要更改jvm本身)。Posix指定posix_spawn()函数,从理论上讲,可以在不复制调用进程的内存映射的情况下实现posix_spawn()函数-
但在Linux上不是这样。



 类似资料:
  • 由于Linux系统的特殊性,G01对于Linux系统的支持主要以内核版本为主,即"uname -a"所显示的版本信息;而不以系统的版本信息为支持标准。 以下表格中为当前G01支持的Linux系统内核版本,安装时请进行参考。 CentOS/RedHat Linux 内核版本 CentOS 7/RedHat Linux 7 CentOS 6/RedHat Linux 6 CentOS 5/RedHat

  • 我正在使用约克托项目来构建 linux os 映像。我使用SUMO版本,所以我有4.14.73内核版本。 问题是我有预编译的linux驱动,版本是4.14.88。 我认为我必须升级我的linux内核,使其成为相同版本的驱动程序。 知道怎么做吗?

  • 本章描述 Linux 内核中的内存管理。在本章中你会看到一系列描述 Linux 内核内存管理框架的不同部分的帖子。 内存块 - 描述早期的 memblock 分配器。 固定映射地址和 ioremap - 描述固定映射的地址和早期的 ioremap 。 kmemcheck - 第三部分描述 kmemcheck 工具。

  • 在我的 amd5700g 上安装了一个 ubuntu22.04 Desktop 发现 linux 内核版本是 6.2.0 但是安装的 ubuntu22.04 Server 版本的 linux 内核是 5.15.0 版本 这个差异是因为 desktop 和 server 版本引起的吗? 但是从我之前的观察发现,好像即便在同一个 ubuntu 版本下(比如 18、20、22)都是 desktop 或者

  • 内核中 kmemcheck 介绍 Linux内存管理章节描述了Linux内核中内存管理;本小节是第三部分。 在本章第二节中我们遇到了两个与内存管理相关的概念: 固定映射地址; 输入输出重映射. 固定映射地址代表虚拟内存中的一类特殊区域, 这类地址的物理映射地址是在编译期间计算出来的。输入输出重映射表示把输入/输出相关的内存映射到虚拟内存。 例如,查看/proc/iomem命令: $ sudo ca

  • 我使用的是spring-boot-starter父版本1.4.0.M3和spring-boot-starter data-solr,在pom文件中没有任何版本,solr-solrj也没有任何版本(它使用的是5.5.1版本)。我想包括solr-core,因为我必须提到版本,如果我添加了版本6.0.0或6.1.0,项目将编译,但在运行时,当我尝试创建SolrConfig对象时失败,错误如下 尝试降低s