汽车之家三面:Linux操作系统里一个进程最多可以创建多少个线程?

2024-01-28 08:58

本文主要是介绍汽车之家三面:Linux操作系统里一个进程最多可以创建多少个线程?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

昨天有位读者**被坑了,**问了我这么个问题:

大致意思就是,他看了一个面经,说虚拟内存是 2G 大小,然后他看了我的图解系统 PDF 里说虚拟内存是 4G,然后他就懵逼了。

其实他看这个面经很有问题,没有说明是什么操作系统,以及是多少位操作系统。

因为不同的操作系统和不同位数的操作系统,虚拟内存可能是不一样多。

Windows 系统我不了解,我就说说 Linux 系统。

Linux面试真题答案地址:Linux面试题(2021最新版)

在 Linux 操作系统中,虚拟地址空间的内部又被分为内核空间和用户空间两部分,不同位数的系统,地址 空间的范围也不同。比如最常⻅的 32 位和 64 位系统,如下所示:

通过这里可以看出:

  • 32 位系统的内核空间占用 1G ,位于最高处,剩下的 3G 是用户空间;
  • 64 位系统的内核空间和用户空间都是 128T ,分别占据整个内存空间的最高和最低处,剩下的中
    间部分是未定义的。

接着,来看看读者那个面经题目:一个进程最多可以创建多少个线程?

这个问题跟两个东西有关系:

  • 进程的虚拟内存空间上限,因为创建一个线程,操作系统需要为其分配一个栈空间,如果线程数量越多,所需的栈空间就要越大,那么虚拟内存就会占用的越多。
  • 系统参数限制,虽然 Linux 并没有内核参数来控制单个进程创建的最大线程个数,但是有系统级别的参数来控制整个系统的最大线程个数。

我们先看看,在进程里创建一个线程需要消耗多少虚拟内存大小?

我们可以执行 ulimit -a 这条命令,查看进程创建线程时默认分配的栈空间大小,比如我这台服务器默认分配给线程的栈空间大小为 8M。

在前面我们知道,在 32 位 Linux 系统里,一个进程的虚拟空间是 4G,内核分走了1G,留给用户用的只有 3G

那么假设创建一个线程需要占用 10M 虚拟内存,总共有 3G 虚拟内存可以使用。于是我们可以算出,最多可以创建差不多 300 个(3G/10M)左右的线程。

如果你想自己做个实验,你可以找台 32 位的 Linux 系统运行下面这个程序:

由于我手上没有 32 位的系统,我这里贴一个网上别人做的测试结果:

如果想使得进程创建上千个线程,那么我们可以调整创建线程时分配的栈空间大小,比如调整为 512k:

$ ulimit -s 512

说完 32 位系统的情况,我们来看看 64 位系统里,一个进程能创建多少线程呢?

我的测试服务器的配置:

  • 64 位系统;
  • 2G 物理内存;
  • 单核 CPU。

64 位系统意味着用户空间的虚拟内存最大值是 128T,这个数值是很大的,如果按创建一个线程需占用 10M 栈空间的情况来算,那么理论上可以创建 128T/10M 个线程,也就是 1000多万个线程,有点魔幻!

所以按 64 位系统的虚拟内存大小,理论上可以创建无数个线程。

事实上,肯定创建不了那么多线程,除了虚拟内存的限制,还有系统的限制。

比如下面这三个内核参数的大小,都会影响创建线程的上限:

  • /proc/sys/kernel/threads-max,表示系统支持的最大线程数,默认值是 14553;
  • /proc/sys/kernel/pid_max,表示系统全局的 PID 号数值的限制,每一个进程或线程都有 ID,ID 的值超过这个数,进程或线程就会创建失败,默认值是 32768;
  • /proc/sys/vm/max_map_count,表示限制一个进程可以拥有的VMA(虚拟内存区域)的数量,具体什么意思我也没搞清楚,反正如果它的值很小,也会导致创建线程失败,默认值是 65530。

那接下针对我的测试服务器的配置,看下一个进程最多能创建多少个线程呢?

我在这台服务器跑了前面的程序,其结果如下:

可以看到,创建了 14374 个线程后,就无法再创建了,而且报错是因为资源的限制。

前面我提到的 threads-max 内核参数,它是限制系统里最大线程数,默认值是 14553。

我们可以运行那个测试线程数的程序后,看下当前系统的线程数是多少,可以通过 top -H 查看。

左上角的 Threads 的数量显示是 14553,与 threads-max 内核参数的值相同,所以我们可以认为是因为这个参数导致无法继续创建线程。

那么,我们可以把 threads-max 参数设置成 99999:

echo 99999 > /proc/sys/kernel/threads-max

设置完 threads-max 参数后,我们重新跑测试线程数的程序,运行后结果如下图:

可以看到,当进程创建了 32326 个线程后,就无法继续创建里,且报错是无法继续申请内存。

此时的上限个数很接近 pid_max 内核参数的默认值(32768),那么我们可以尝试将这个参数设置为 99999:

echo 99999 > /proc/sys/kernel/pid_max

设置完 pid_max 参数后,继续跑测试线程数的程序,运行后结果创建线程的个数还是一样卡在了 32768 了。

当时我也挺疑惑的,明明 pid_max 已经调整大后,为什么线程个数还是上不去呢?

后面经过查阅资料发现,max_map_count 这个内核参数也是需要调大的,但是它的数值与最大线程数之间有什么关系,我也不太明白,只是知道它的值是会限制创建线程个数的上限。

然后,我把 max_map_count 内核参数也设置成后 99999:

echo 99999 > /proc/sys/kernel/pid_max 

继续跑测试线程数的程序,结果如下图:

当创建差不多 5 万个线程后,我的服务器就卡住不动了,CPU 都已经被占满了,毕竟这个是单核 CPU,所以现在是 CPU 的瓶颈了。

我只有这台服务器,如果你们有性能更强的服务器来测试的话,有兴趣的小伙伴可以去测试下。

接下来,我们换个思路测试下,把创建线程时分配的栈空间调大,比如调大为 100M,再大就会创建线程失败。

ulimit -s 1024000

设置完后,跑测试线程的程序,其结果如下:

总共创建了 26390 个线程,然后就无法继续创建了,而且该进程的虚拟内存空间已经高达 25T,要知道这台服务器的物理内存才 2G。

为什么物理内存只有 2G,进程的虚拟内存却可以使用 25T 呢?

因为虚拟内存并不是全部都映射到物理内存的,程序是有局部性的特性,也就是某一个时间只会执行部分代码,所以只需要映射这部分程序就好。

你可以从上面那个 top 的截图看到,虽然进程虚拟空间很大,但是物理内存(RES)只有使用了 400M+。

好了,简单总结下:

  • 32 这个系统,用户态的虚拟空间只有 3G,如果创建线程时分配的栈空间是 10M,那么一个进程最多只能创建 300 个左右的线程。

64 系统,用户态的虚拟空间大到有 128T,理论上不会受虚拟内存大小的限制,而会受系统的参数或性能限制。

原文链接:https://mp.weixin.qq.com/s/eC599TS_0kfwDK4LGgPa1g

这篇关于汽车之家三面:Linux操作系统里一个进程最多可以创建多少个线程?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/653119

相关文章

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包, 通常我们会使用nohup直接启动,但是还是需要手动停止然后再次启动, 那如何更优雅的在服务器上启动jar包呢,让我们一起探讨一下吧。 1、初版 第一个版本是常用的做法,直接使用nohup后台启动jar包, 并将日志输出到当前文件夹n