Linux OOM

OOM是什么


为什么会发生 OOM

OOM(Out of Memory)错误发生在系统内存耗尽时,无法为新的进程或现有进程分配足够的内存。具体原因包括:

  1. 内存泄漏:程序在运行过程中申请了内存但没有正确释放,导致内存逐渐耗尽。

  2. 内存使用过大:某些程序或进程在某一时刻申请了过多的内存,超过了系统的实际可用内存资源。

  3. 共享内存和缓存:系统中的其他进程或服务占用了大量的内存资源,导致当前进程无法获得足够的内存空间。

  4. 内核内存管理:操作系统内核在管理内存时,也会占用一定的内存资源。当内核内存管理不当或内核模块占用过多内存时,也会导致内存不足。

OOM 的条件

Linux 系统中的 OOM Killer 机制会在系统内存耗尽时启动,以确保系统继续运行。OOM Killer 的触发条件包括:

  1. 内存分配失败:当系统尝试分配内存但失败时,会触发 OOM Killer。

  2. 内存压力:系统检测到内存压力过大,无法满足当前需求时,会触发 OOM Killer。

  3. 内存释放尝试失败:系统尝试通过清理缓存、交换内存等方式释放内存,但未能成功时,会触发 OOM Killer.

OOM Killer 的工作机制

  1. 评分机制:系统会为每个进程分配一个 oom_score 值,基于进程占用的内存量、运行时长以及是否设置了特定的保护标志等因素计算得出。当内存紧张时,评分最高的进程最先被 OOM Killer 终止.

  2. 选择目标进程:在获得所有运行进程的评分后,OOM Killer 会选择 oom_score 最高的进程作为终止目标。某些特殊进程可能会设置负的 oom_adj,以降低被 OOM Killer 终止的可能性.

 

OOM 分类


  • JVM OOM:主要发生在Java虚拟机内部,通常与Java应用程序的内存管理有关。解决方法通常涉及调整JVM参数、优化代码或增加内存。

  • 系统 OOM:发生在操作系统层面,通常与系统资源管理有关。解决方法通常涉及增加物理内存、调整系统配置或优化系统资源使用

 

系统OOM时内存分类


在 Linux 系统中,内存分类可以分为以下几种:

  1. 堆内存(Heap Memory)

    • 堆内存是动态分配的内存,用于存储程序运行时动态分配的对象和数据结构。

    • 通过 malloccallocrealloc 等函数进行分配,通过 free 函数进行释放。

    • 堆内存的大小可以在程序运行时动态调整。

  2. 栈内存(Stack Memory)

    • 栈内存用于存储函数调用时的局部变量、函数参数和返回地址。

    • 栈内存是自动分配和释放的,当函数调用时分配内存,函数返回时释放内存。

    • 栈内存的大小通常是固定的,由操作系统分配。

  3. 共享内存(Shared Memory)

    • 共享内存是一种进程间通信(IPC)机制,允许多个进程共享同一块内存区域。

    • 通过 shmgetshmatshmdt 等系统调用进行分配和管理。

    • 共享内存可以用于高效的数据交换,因为它避免了数据的复制。

  4. 内核内存(Kernel Memory)

    • 内核内存用于存储操作系统内核和内核模块的数据结构和代码。

    • 内核内存是由操作系统管理的,用户进程无法直接访问。

    • 内核内存包括内核堆、内核栈和内核缓存等。

  5. 缓存和缓冲区(Cache and Buffers)

    • 缓存用于存储频繁访问的数据,以提高访问速度。

    • 缓冲区用于临时存储数据,以便在数据传输过程中进行处理。

    • 缓存和缓冲区由操作系统自动管理,用户无需手动干预。

 

Java服务运行中产生的额外内存


Java服务在运行中除了堆内内存, 还会产生以下堆外内存

堆外内存(Off-Heap Memory)

堆外内存是指不由 JVM 管理的内存区域,通常通过直接内存(Direct Memory)或本地内存(Native Memory)进行分配。堆外内存包括以下部分:

  • 直接内存(Direct Memory):通过 ByteBuffer.allocateDirect() 方法分配的内存,用于高效的 I/O 操作。

  • 本地方法栈(Native Method Stack):用于存储本地方法调用的局部变量和参数,JNI 调用或者第三方库(如 Netty、FFmpeg)可能分配内存而未释放。

  • 共享内存(Shared Memory):用于进程间通信(IPC),允许多个进程共享同一块内存区域。

  • 线程的栈内存: 每个线程分配栈内存,线程数量过多会快速耗尽内存。

  • 系统内核内存: Socket 缓冲区、文件句柄、TCP 缓冲区等,都可能由内核维护并消耗内存

  • 动态加载的类: 不断加载类,元空间会增加

  • 内存映射文件 (Memory-Mapped Files): JVM 或底层库(如 NIO 文件通道)可能使用内存映射文件将磁盘内容直接映射到内存, 通过 mmap 系统调用分配, 不占用堆内内存消耗系统内存

 

posted @ 2024-12-09 15:23  MacoPlus  阅读(12)  评论(0编辑  收藏  举报