科普

226 阅读10分钟

内存

1. 进程申请内存超过系统分配内存的表现

当一个进程申请的内存超过了系统给它分配的内存时,应用和系统可能会出现以下几种表现:

  • 页面置换(Swap):操作系统会尝试将不常使用的内存页从物理内存中移到硬盘上的交换空间(swap),从而为新的内存需求腾出空间。这会导致系统性能变慢,因为硬盘访问速度远远慢于物理内存。

  • 内存不足 (Out of Memory, OOM):如果系统的物理内存和交换空间都用尽,系统会触发 OOM 机制,可能会终止占用大量内存的进程(通过 OOM killer)以释放资源。应用程序可能因此崩溃或被强制退出。

  • 内存分配失败:如果进程的内存请求超出了操作系统能够提供的范围,malloc 或 mmap 等系统调用会返回 NULL,表示分配失败。应用程序可以通过捕获该错误并处理,如抛出异常或中止。

  • 卡顿或失去响应:在内存耗尽并频繁使用 Swap 的情况下,系统的响应速度会显著下降,甚至可能出现短暂的无响应状态,尤其在 I/O 负载较大的情况下。

2. 操作系统给进程分配内存的机制

操作系统的内存管理通过 虚拟内存机制 实现。虚拟内存使得每个进程都拥有一个独立的、连续的地址空间,而实际的物理内存是操作系统根据需要分配的。主要机制包括:

  • 按需分配 (Lazy Allocation):当进程请求内存时,操作系统不会立即分配物理内存,而是仅为其分配虚拟地址空间。实际的物理内存分配会在该地址空间被首次访问时触发,通过页面错误(page fault)分配实际内存页。

  • 分页 (Paging):现代操作系统通常采用分页机制,将内存分割为固定大小的页(如 4KB),虚拟内存的地址映射到物理内存的页框上。进程看到的是虚拟内存,而硬件中的 MMU(内存管理单元)负责将虚拟地址转换为物理地址。

  • 页面换入/换出 (Swapping):当物理内存不足时,操作系统可以将不常用的内存页换出到硬盘(交换空间),腾出内存用于更活跃的进程。

  • 内存映射文件 (Memory-Mapped Files):通过 mmap,进程可以将文件映射到虚拟内存,这样可以将文件 I/O 映射为内存访问,而不需要手动读写文件。

3. 操作系统如何实现进程的内存保护

  1. 虚拟内存:

    • 每个进程都有自己的页表,用于将虚拟地址转换为物理地址。
    • 页表由操作系统管理,进程无法直接修改。
    • 这种机制确保了进程只能访问分配给它的内存区域。
  2. 内存访问权限:

    • MMU(内存管理单元)在每次内存访问时检查权限。
    • 页表项中包含权限位,指定了读、写、执行权限。
    • 违反权限的访问会触发页面错误,由操作系统处理。
  3. 地址空间隔离:

    • 内核空间和用户空间分离。
    • 用户进程不能直接访问内核空间,需要通过系统调用。
  4. 进程切换时的上下文切换:

    • 切换进程时,CPU的页表基址寄存器(PTBR)会被更新,指向新进程的页表。
    • 这确保了每个进程只能访问自己的地址空间。
  5. 缓冲区溢出保护:

    • 许多现代操作系统实现了栈保护机制,如栈canary。
    • 这些机制可以检测并防止缓冲区溢出攻击。
  6. 地址空间布局随机化(ASLR):

    • 随机化进程的内存布局,增加攻击难度。
    • 使得攻击者难以预测特定内存区域的位置。
  7. 硬件支持:

    • 现代处理器提供不同的特权级别(如x86的环)。
    • 某些指令和内存区域只能在高特权级别访问。
  8. 内存加密:

    • 一些高安全性要求的系统可能会对内存进行加密。
    • 这可以防止物理内存攻击,如冷启动攻击。

cpu

CPU占用情况(CPU Usage)是指处理器在一定时间段内用于处理各种任务的时间百分比。它反映了系统负载的程度,即CPU有多少资源被使用或空闲。CPU占用情况可以通过不同的视角来观察,通常分为系统层面进程层面。以下是关于CPU占用情况的详细说明:

1. CPU占用率的计算

CPU占用率通常以百分比表示,计算方式如下:

CPU 占用率 = (CPU在活动状态的时间 / 总时间) × 100%
  • 活动状态的时间:包括用户进程、系统进程、等待I/O等。
  • 总时间:包括活动时间和空闲时间。

计算CPU占用率时,我们通常按每个核心来计算。例如,四核CPU的最大总利用率为400%。


2. 查看CPU占用情况的工具

2.1 Linux系统中的工具

  • top 命令
    top 是Linux下的实时系统监控工具,能够动态显示系统的各种资源使用情况,包括CPU占用情况。它提供了每个进程的CPU占用率(%CPU),以及整体的CPU负载。

    top
    

    输出说明:

    • us:用户空间占用的CPU时间,表示应用程序(非内核)使用的CPU百分比。
    • sy:内核空间占用的CPU时间,表示系统(内核)使用的CPU百分比。
    • ni:调整过优先级的进程所占用的CPU时间。
    • id:CPU空闲时间,表示CPU没有执行任何任务时的时间百分比。
    • wa:等待I/O操作的时间,表示CPU等待I/O操作完成的时间百分比。
    • st:被虚拟机占用的时间。
  • htop 命令
    htoptop 的增强版,提供了更友好的界面,可以直观显示每个核心的CPU使用情况,并支持上下箭头快速查看进程资源占用情况。

  • mpstat 命令
    mpstat 提供更详细的CPU使用情况,可以查看每个CPU核心的使用率,以及用户态、系统态、I/O等待等不同时间段的占用比例。

    mpstat -P ALL 1
    
  • sar 命令
    sar 是系统性能分析工具,可以监控包括CPU、内存、网络等资源使用情况,并支持历史记录的查看。

    sar -u 1
    
    • sar -u 显示整体的CPU使用率。
    • sar -P ALL 显示所有CPU核心的使用率。

2.2 Windows系统中的工具

  • 任务管理器(Task Manager)

    • 通过按 Ctrl + Shift + Esc 可以打开Windows任务管理器,在“性能”选项卡下查看每个核心的CPU使用情况和整体的CPU占用率。
    • 在“进程”选项卡中,可以查看每个进程的CPU占用率。
  • 资源监视器(Resource Monitor)

    • 通过任务管理器打开“资源监视器”,可以更详细地查看每个核心、每个进程的CPU使用情况,并跟踪进程的行为。
  • perfmon(性能监视器)

    • Windows自带的性能监视器,可以用于长期监控和记录CPU的占用情况,并生成分析报告。

2.3 Mac系统中的工具

  • 活动监视器(Activity Monitor)

    • 通过 Spotlight 搜索“Activity Monitor”,可以实时查看系统的资源使用情况,包括CPU的占用率。
    • 活动监视器会显示每个进程的CPU使用百分比,空闲时间以及每个核心的负载情况。
  • top 命令

    • macOS 中也支持 top 命令,与Linux系统类似,能够显示系统和进程的CPU占用情况。

3. CPU占用的不同类型

3.1 用户态CPU占用(User Space CPU Usage)

  • 定义:用户态CPU占用是指运行在用户空间的应用程序(不包括内核代码)所消耗的CPU时间。一般来说,大部分普通应用程序的代码都运行在用户态。
  • 标记:在 top 命令中以 us 表示。

3.2 内核态CPU占用(Kernel Space CPU Usage)

  • 定义:内核态CPU占用是指运行在操作系统内核中的代码(如系统调用、设备驱动程序、网络处理等)所消耗的CPU时间。内核态占用时间过高可能意味着频繁的系统调用或设备I/O。
  • 标记:在 top 命令中以 sy 表示。

3.3 I/O等待(I/O Wait)

  • 定义:指CPU空闲时等待磁盘或网络I/O完成的时间。高 wa 值表示系统的I/O设备性能可能是瓶颈,CPU大部分时间都在等待I/O操作完成。
  • 标记:在 top 命令中以 wa 表示。

3.4 中断处理时间(Interrupt Time)

  • 定义:用于处理硬件中断的时间。硬件中断是系统硬件向处理器发出的一种信号,表示有外部事件(如设备完成I/O操作)需要处理。
  • 标记:在某些工具中以 hi 表示硬中断(硬件中断)时间,以 si 表示软中断(软件中断)时间。

3.5 空闲时间(Idle Time)

  • 定义:表示CPU没有执行任何任务时的时间。高 id 值表明CPU大部分时间处于空闲状态。
  • 标记:在 top 命令中以 id 表示。

3.6 偷取时间(Steal Time)

  • 定义:表示虚拟机运行时,虚拟机管理程序(如KVM、Xen等)将CPU资源分配给其他虚拟机的时间。st 值越高,说明虚拟机在争夺物理CPU资源时,等待时间越长。
  • 标记:在 top 命令中以 st 表示。

4. 高CPU占用的常见原因

  • 计算密集型任务:如果程序中有大量的计算任务(如图像处理、视频编码等),会导致CPU长时间处于繁忙状态。
  • 频繁的I/O操作:如果程序频繁进行磁盘I/O或网络I/O操作,可能导致I/O等待时间长,进而影响CPU的有效使用。
  • 死循环或无效的长时间执行任务:代码中的死循环、无限递归等逻辑错误可能导致CPU资源被无休止地占用。
  • 垃圾回收(GC):Java程序中,频繁的垃圾回收可能导致CPU使用率较高,尤其是当内存资源紧张时。
  • 内核问题或驱动问题:某些情况下,系统内核或驱动程序出现问题,导致CPU长期处于内核态高占用。
  • 多线程竞争问题:如果多个线程频繁争抢锁,会导致上下文切换增加,CPU使用率上升。

5. 优化高CPU占用的策略

  • 代码优化:减少不必要的计算,避免死循环和无效的高复杂度算法。
  • 任务分配:将计算密集型任务分布到多个线程或多核CPU上,充分利用CPU资源。
  • 异步I/O:在程序中使用异步I/O,减少CPU因I/O等待时间而处于空闲状态。
  • 调优垃圾回收器(GC):如果是Java应用,可以通过调整垃圾回收策略来减少GC引发的CPU占用过高。
  • 负载均衡:如果是服务器系统,可以通过负载均衡将任务分散到多台服务器,降低单台机器的CPU压力。
  • 硬件升级:如果CPU长期处于高负载状态,并且无法通过软件优化解决,可能需要考虑升级处理器或增加CPU核心数量。