首页 > 系统相关 >不同平台下对进程资源进行限制(CPU与内存)

不同平台下对进程资源进行限制(CPU与内存)

时间:2024-08-22 15:28:28浏览次数:7  
标签:限制 作业 内存 进程 sa rlim CPU

不同平台下对进程资源进行限制(CPU与内存)

因实际工作中发现, 如果不对某些进程硬件资源进行限制, 可能某个进程会把操作系统资源耗尽, 导致操作系统死机等问题出现。

于是就想, 是否有什么方法可以限制指定进程内存使用上限, 避免其无上限申请内存。

Windows

Windows 平台可通过作业对象对进程所占资源进行限制。

作业对象允许将进程组作为一个单元进行管理。 作业对象是可访问的、安全的、可共享的对象,用于控制与其关联的进程的属性。 针对某个作业对象执行的操作会影响与该作业对象关联的所有进程。 示例包括强制实施工作集大小和进程优先级等限制,或终止与作业关联的所有进程。

创建一个作业对象

若要创建作业对象,需 CreateJobObject 函数。 创建作业时,不会与作业关联任何进程。

若要将进程与作业相关联,请使用 AssignProcessToJobObject 函数。 进程与作业关联后,无法断开关联。 一个进程可以与嵌套作业层次结构中的多个作业相关联。

如下代码展示了如何创建一个作业对象, 以及与当前进程进行关联:

// 创建 Job 对象
HANDLE hJob = CreateJobObject(nullptr, nullptr);
if (hJob == nullptr) {
    std::cerr << "Failed to create Job object" << std::endl;
    return 1;
}

// 此处配置作业对象 

// 将当前进程加入 Job 对象
if (!AssignProcessToJobObject(hJob, GetCurrentProcess())) {
    std::cerr << "Failed to assign process to Job object" << std::endl;
    CloseHandle(hJob);
    return 1;
}

//...

CloseHandle(hJob);

若某进程与作业对象关联后, 在该进程中调用CreateProcess创建任何子进程也将与作业进行关联。

判断某进程是否在作业中运行, 可调用IsProcessInJob得知

若要终止当前与作业对象关联的所有进程,请使用TerminateJobObject 函数。

资源限制

资源限制主要通过调用SetInformationJobObject, 支持的限制选项有:

使用 SP3 和 Windows Server 2003 的 Windows XP:SetInformationJobObject 函数可用于为与作业对象关联的所有进程设置安全限制。 从 Windows Vista 开始,必须为与作业对象关联的每个进程单独设置安全限制

可通过调用QueryInformationJobObject获取当前有哪些限制。

内存限制示例

限制进程最大分配100MB内存:

// 设置 Job 对象限制
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo = {};
jobInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY;
jobInfo.ProcessMemoryLimit = 100 * 1024 * 1024;  // 100 MB

if (!SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jobInfo, sizeof(jobInfo))) {
    std::cerr << "Failed to set Job object information" << std::endl;
    CloseHandle(hJob);
    return 1;
}

CPU限制示例

如下示例展示了如何将CPU使用率限制在20%:

JOBOBJECT_CPU_RATE_CONTROL_INFORMATION info;
info.CpuRate = 20 * 100;
info.ControlFlags = JOB_OBJECT_CPU_RATE_CONTROL_ENABLE | JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP;
if (!::SetInformationJobObject(hJob, JobObjectCpuRateControlInformation, &info, sizeof(info))){
    std::cerr << "Failed to set Job object information" << std::endl;
    return 1;
    
}

不能将 CpuRate 设置为 0。 如果 CpuRate 为 0, 则SetInformationJobObject返回 INVALID_ARGS。

经实测, 限制CPU会有10%的上限幅度。

Linux

Linux 通过调用setrlimit对进程的CPU、内存等作出限制。 其效果与执行shell命令ulimit 一样。

其函数签名如下:

int setrlimit(int resource, const struct rlimit *rlim);

其中 resource可选参数如下:

  • RLIMIT_AS: 用于设置当前进程最大的虚拟地址空间大小。单位字节。 此限制直接影响brkmmapmremap, 失败时其errno等于ENOMEM
  • RLIMIT_CORE:用于限制coredump file大小,若设置为0, 则不会生成该文件。
  • RLIMIT_CPU: 设置的是进程能够使用的最大 CPU 时间总量(以秒为单位)。当进程的 CPU 时间总量达到软限制时,操作系统会向进程发送SIGXCPU信号。默认情况下,这会终止进程。而如果信号忽略, 继续占用CPU, 内核将继续每秒发送一次SIGXCPU信号, 直到达到硬限制, 最终触发SIGKILL。
  • 其他限制参考 https://linux.die.net/man/2/setrlimit

struct rlimit结构如下:

struct rlimit {
    rlim_t rlim_cur;  /* Soft limit */
    rlim_t rlim_max;  /* Hard limit (ceiling for rlim_cur) */
};

内存限制示例

#include <sys/resource.h>

void setMemoryLimit(size_t limit_in_bytes) {
    struct rlimit rl;
    rl.rlim_cur = limit_in_bytes;
    rl.rlim_max = limit_in_bytes;

    if (setrlimit(RLIMIT_AS, &rl) == -1) {
        fprintf(stderr, "Error setting memory limit:%s\n", strerror(errno));
    }
}

CPU 限制示例

void setCPULimit(size_t second)
{
    struct rlimit rl;
    rl.rlim_cur = second;
    rl.rlim_max = second * 3;

    if (setrlimit(RLIMIT_CPU, &rl) == -1) {
        fprintf(stderr, "Error setting memory limit:%s\n", strerror(errno));
    }
}

当超过限制的时候触发的信号处理, 确保设置信号SA_RESTART标志位,避免触发一次后被重置为默认信号处理:


void sign_handler(int signno)
{
    printf("Trigger the %s(%d) signal.\n","SIGXCPU", signno);
}


struct sigaction sa;
sa.sa_handler = sign_handler;
sigemptyset(&sa.sa_mask);
// 执行SIGINT时, 不允许被SIGQUIT中断
sigaddset(&sa.sa_mask, SIGQUIT);
sa.sa_flags = SA_RESTART;

if (sigaction(SIGXCPU, &sa, NULL) == -1){
    printf("Failed to set SIGXCPU signal handler.\n");
    return 1;
}

以上CPU限制较为严格或带点强制, 达到约束将导致程序退出。 另一种相对较为友好的方式就是设置进程的nice优先级, 它不会限制进程可以使用的 CPU 时间总量,而是影响调度程序的行为,使低优先级的进程在竞争 CPU 时间时处于劣势。

使用nice命令启动进程, 设置其nice值为10, nice值可设置范围为[-20,19]

nice -n 10 ./xxx_program

设置较低的优先级, 使其占用的CPU时间降低。

nice 只是对调度程序的建议,并不保证精确的 CPU 使用限制。它可能会影响一个进程的响应时间,但不会严格限制它的 CPU 时间。

其他方式

其他方式包括通过配置systemd, cgroupdocker等方式实现对资源的限制。 从本质上说, Systemd的配置与cgroups的配置是一套机制。 systemd依赖cgroups而实现。

标签:限制,作业,内存,进程,sa,rlim,CPU
From: https://www.cnblogs.com/quenwaz/p/18373958

相关文章

  • 【C语言进阶】数据如何安家?C语言内存中的存储艺术深度解析
    ......
  • 内存的操作
    我们对于内存的操作借助于string.h这个库提供的内存操作函数。内存填充头文件:#include<string.h>函数原型:void*memset(void*s,intc,size_tn);函数功能:填充s开始的堆内存空间前n个字节,使得每个字节值为c。函数参数:void*s:待操作内存首地址。intc:填充的字节数据......
  • 进程间通信方式详解
    正文每个进程的用户地址空间都是独立的,一般而言是不能互相访问的,但内核空间是每个进程都共享的,所以进程之间要通信必须通过内核。Linux内核提供了不少进程间通信的机制,我们来一起瞧瞧有哪些?管道如果你学过Linux命令,那你肯定很熟悉「|」这个竖线。$psauxf|grep......
  • 【OS系列】程序、进程与线程之区别大揭秘,一图读懂胜千言
    1.程序(Program)程序是一组指令的集合,它存储在磁盘上,是一个静态的实体。程序本身并不执行任何操作,它只是提供了一个执行的蓝图。例如,一个编译好的可执行文件(如Windows的.exe文件)就是一个程序。2.进程(Process)进程是程序的一次执行实例,是操作系统进行资源分配和调度的基本......
  • 进程(2) wait、exec函数族
    目录1. fork() 函数功能使用时注意事项2. exit() 函数功能使用时注意事项3. wait() 函数功能使用时注意事项总结wait()异常信号结束waitpidexec函数族execl()execlp()execvexecvpfork()、exit() 和 wait() 函数在进程管理中扮演着重要的角色,它们......
  • 引发C++程序内存泄漏的常见原因分析与排查方法总结
    目录1、概述2、内存泄漏与程序的位数3、调用哪些接口去动态申请内存?4、引发内存泄漏的常见原因总结4.1、通过malloc/new等动态申请的内存,在使用完后,没有调用free/delete去释放(也可能是调用了上面讲到的HeapAlloc或VirtualAlloc等API接口)4.2、函数调用者调用内部申请内存......
  • Python被远程主机强制关闭后怎么自动重新运行进程
    要实现Python程序在被远程主机强制关闭后能够自动重新运行,我们可以采用几种方法,但最直接且常用的方法之一是结合操作系统级的工具或脚本。在Linux系统中,我们可以使用cron作业或者systemd服务来实现这一功能;在Windows系统中,可以使用任务计划程序。但在这里,为了提供一个跨平台的、更......
  • IPC对象通信方式---共享内存 | 网络通信 -编程
    共享内存共享内存机制其允许两个或多个进程共享一个给定的存储区,这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取错做读出,从而实现了进程间的通信。是内核预留的内存空间,最......
  • XSI机制的进程间通信
    XSI机制的进程间通信1、XSI介绍:什么是XSI:X/Open国际联盟有限公司是一个欧洲基金会,它的建立是为了向UNIX环境提供标准,XSI是X/OpenSystemInterface的缩写,也就是X/Open设计的系统接口。X/Open的主要的目标是促进对UNIX系统、接口、网络和应用的开放式系统协议的制定。它还促......
  • 线程与进程的区别(多进程与多线程)
    线程与进程的区别(多进程与多线程)资源:进程采用虚拟空间+用户态/内核态机制,所以就导致进程与进程之间是互相独立的,各自的资源不可见。在同一进程中的各个线程都可以共享该进程所拥有的资源。多进程之间资源是独立的,多线程之间资源是共享的。通信:由于进程之间是互相独立的,需......