You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

页缓存是否属于Java堆外内存?Spark K8s任务OOM排查

页缓存是否属于JVM堆外内存?Spark任务K8s环境OOM排查

核心问题

确认:Java进程以非Direct_IO模式向磁盘写入文件时,操作系统生成的页缓存(page cache)是否属于JVM堆外内存?

背景

在K8s环境运行Scala Spark任务,已设置0.2的内存开销比例,但任务频繁因OOM被终止。Spark UI显示堆内存与堆外内存的峰值总和远低于容器内存限制,但dmesg日志显示Java进程被杀死时占用了容器全部内存,怀疑是页缓存占用剩余内存导致OOM。

资源占用对比

Spark UI统计数据

已终止的executor1内存占用:

  • 堆内存:21.1 GiB
  • 堆外内存:142.2 MiB

dmesg日志记录(进程被杀死时)

[Mon Feb 20 03:36:35 2023] memory: usage 25907200kB, limit 25907200kB, failcnt 1911352
[Mon Feb 20 03:36:35 2023] memory+swap: usage 0kB, limit 9007199254740988kB, failcnt 0
[Mon Feb 20 03:36:35 2023] kmem: usage 106724kB, limit 9007199254740988kB, failcnt 0
[Mon Feb 20 03:36:35 2023] Memory cgroup stats for /kubepods/pod320ce7f2-aa63-4f3f-9fbe-2ae0be48736c:
[Mon Feb 20 03:36:35 2023] anon 25102856192
                           file 1315708928
                           kernel_stack 1069056
                           slab 52314112
                           sock 0
                           shmem 0
                           file_mapped 0
                           file_dirty 1316130816
                           file_writeback 0
                           anon_thp 20558381056
                           inactive_anon 0
                           active_anon 25102508032
                           inactive_file 328622080
                           active_file 987414528
                           unevictable 0
                           slab_reclaimable 43982848
                           slab_unreclaimable 8331264
                           pgfault 11556633
                           pgmajfault 0
                           workingset_refault 814704
                           workingset_activate 165
                           workingset_nodereclaim 0
                           pgrefill 12258140
                           pgscan 15669889
                           pgsteal 2556626
                           pgactivate 13111197
                           pgdeactivate 12258004
                           pglazyfree 0
                           pglazyfreed 0
                           thp_fault_alloc 11253
                           thp_collapse_alloc 0
[Mon Feb 20 03:36:35 2023] Tasks state (memory values in pages):
[Mon Feb 20 03:36:35 2023] [  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
[Mon Feb 20 03:36:35 2023] [ 168097] 65535 168097      241        1    28672        0          -998 pause
[Mon Feb 20 03:36:35 2023] [ 168142]     0 168142      571      192    49152        0          -997 tini
[Mon Feb 20 03:36:35 2023] [ 168217]     0 168217  7542445  6135546 50069504        0          -997 java

内核调用栈

[Mon Feb 20 03:36:55 2023] Call Trace:
[Mon Feb 20 03:36:55 2023]  dump_stack+0x57/0x6d
[Mon Feb 20 03:36:55 2023]  dump_header+0x4f/0x200
[Mon Feb 20 03:36:55 2023]  oom_kill_process+0xec/0x140
[Mon Feb 20 03:36:55 2023]  out_of_memory+0x117/0x570
[Mon Feb 20 03:36:55 2023]  mem_cgroup_out_of_memory+0xbb/0xd0
[Mon Feb 20 03:36:55 2023]  try_charge+0x762/0x7c0
[Mon Feb 20 03:36:55 2023]  ? ext4_do_update_inode+0x4ff/0x7b0
[Mon Feb 20 03:36:55 2023]  mem_cgroup_try_charge+0x75/0x190
[Mon Feb 20 03:36:55 2023]  __add_to_page_cache_locked+0x21a/0x3d0
[Mon Feb 20 03:36:55 2023]  ? scan_shadow_nodes+0x30/0x30
[Mon Feb 20 03:36:55 2023]  add_to_page_cache_lru+0x4f/0xd0
[Mon Feb 20 03:36:55 2023]  pagecache_get_page+0xea/0x2c0
[Mon Feb 20 03:36:55 2023]  grab_cache_page_write_begin+0x23/0x40
[Mon Feb 20 03:36:55 2023]  ext4_da_write_begin+0x11a/0x450
[Mon Feb 20 03:36:55 2023]  generic_perform_write+0xb3/0x1b0
[Mon Feb 20 03:36:55 2023]  __generic_file_write_iter+0x1aa/0x1d0
[Mon Feb 20 03:36:55 2023]  ? generic_write_checks+0x68/0xc0
[Mon Feb 20 03:36:55 2023]  ext4_file_write_iter+0xbd/0x360
[Mon Feb 20 03:36:55 2023]  ? futex_wake+0x8f/0x180
[Mon Feb 20 03:36:55 2023]  new_sync_write+0x125/0x1c0
[Mon Feb 20 03:36:55 2023]  __vfs_write+0x29/0x40
[Mon Feb 20 03:36:55 2023]  vfs_write+0xb1/0x1a0
[Mon Feb 20 03:36:55 2023]  ksys_write+0xa7/0xe0
[Mon Feb 20 03:36:55 2023]  __x64_sys_write+0x1a/0x20
[Mon Feb 20 03:36:55 2023]  do_syscall_64+0x5e/0x200
[Mon Feb 20 03:36:55 2023]  entry_SYSCALL_64_after_hwframe+0x44/0xa9

结论与解决方案

1. 页缓存不属于JVM堆外内存

JVM堆外内存指JVM直接管理的非堆内存区域,包括DirectByteBuffer、JNI分配内存、Metaspace、Code Cache等。而操作系统页缓存是内核层面独立管理的文件缓存,完全脱离JVM内存统计范畴,不会被Spark UI计入堆外内存。

2. OOM原因确认

从dmesg日志的file字段(约1.22GiB)和调用栈可以看出,OOM发生在写入文件时向页缓存分配内存的过程中。K8s容器内存限制针对整个Pod的所有内存使用(用户进程内存、内核页缓存、Slab等),而Spark UI仅统计JVM自身内存,因此页缓存占用过多会导致Pod总内存超限,触发OOM Killer杀死Java进程。

3. 解决方案建议

  • 使用Direct IO绕过页缓存:配置Spark输出使用Direct IO(如HDFS的dfs.direct.io参数),直接写入磁盘,避免生成页缓存。
  • 调整容器内存配置:适当增加容器内存限制,为页缓存预留空间;或配置K8s QoS为Burstable,允许一定内存超用(需集群支持)。
  • 优化Spark写入策略:合并输出文件,减少小文件数量;采用异步、批量写入方式,降低页缓存瞬时占用。
  • 调整内核页缓存回收策略:通过sysctl修改vm.dirty_ratio、vm.dirty_background_ratio等参数,让内核更及时刷入脏页,释放页缓存内存。

内容的提问来源于stack exchange,提问作者Mifan Indian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 11:45:26