Native Memory Tracking 与 RSS的差异问题
一 问题现象
前一段时间用nmt查看jvm进程的栈区占用的内存大小。测试代码如下
public class ThreadOOM {public static void main(String[] args) {int i = 1;while (i < 3000) {Thread thread = new TestThread();thread.start();System.out.println("thread : " + i);i++;}}
}class TestThread extends Thread {@Overridepublic void run() {while (true) {try {Thread.sleep(Long.MAX_VALUE);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
启动命令
nohup java -Xms2G -Xmx2G -XX:MaxMetaspaceSize=512M -XX:NativeMemoryTracking=detail ThreadOOM &
用native memory tracking查看内存占用
jcmd 37898 VM.native_memory scale=MB
37898:Native Memory Tracking:Total: reserved=9366MB, committed=8211MB
- Java Heap (reserved=2048MB, committed=2048MB)(mmap: reserved=2048MB, committed=2048MB)- Class (reserved=1039MB, committed=12MB)(classes #433)(malloc=7MB #3218)(mmap: reserved=1032MB, committed=5MB)- Thread (reserved=6046MB, committed=6046MB)(thread #3017)(stack: reserved=6032MB, committed=6032MB)(malloc=10MB #18096)(arena=3MB #6029)- Code (reserved=130MB, committed=3MB)(mmap: reserved=130MB, committed=2MB)- GC (reserved=83MB, committed=83MB)(malloc=8MB #123)(mmap: reserved=75MB, committed=75MB)- Internal (reserved=17MB, committed=17MB)(malloc=17MB #34406)- Symbol (reserved=1MB, committed=1MB)(malloc=1MB #110)- Native Memory Tracking (reserved=1MB, committed=1MB)(tracking overhead=1MB)
显示线程占用了6G左右,jvm总共committed了8G左右。
使用top查看,常驻物理内存(RES)才占用了139M,这个和nmt显示的差距太大了吧!commited内存不就应该是RES的大小吗?

二 jdk8申请内存的源码分析
我看的jdk的源码:https://github.com/openjdk/jdk
分支: jdk8-b120
文件位置: hotspot/src/os/linux/vm/os_linux.cpp
reserve内存
char* os::reserve_memory(size_t bytes, char* requested_addr,size_t alignment_hint) {return anon_mmap(requested_addr, bytes, (requested_addr != NULL));
}static char* anon_mmap(char* requested_addr, size_t bytes, bool fixed) {char * addr;int flags;flags = MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS;if (fixed) {assert((uintptr_t)requested_addr % os::Linux::page_size() == 0, "unaligned address");flags |= MAP_FIXED;}// Map uncommitted pages PROT_READ and PROT_WRITE, change access// to PROT_EXEC if executable when we commit the page.addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE,flags, -1, 0);if (addr != MAP_FAILED) {if ((address)addr + bytes > _highest_vm_reserved_address) {_highest_vm_reserved_address = (address)addr + bytes;}}return addr == MAP_FAILED ? NULL : addr;
}
commit内存
// NOTE: Linux kernel does not really reserve the pages for us.
// All it does is to check if there are enough free pages
// left at the time of mmap(). This could be a potential
// problem.
bool os::commit_memory(char* addr, size_t size, bool exec) {int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;uintptr_t res = (uintptr_t) ::mmap(addr, size, prot,MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0);return res != (uintptr_t) MAP_FAILED;
}
不管是reserve还是commit内存,背后都是调用mmap函数
三 mmap函数分析
函数原型
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
mmap主要做文件映射,也可以用来为进程申请内存。jdk显然是用来申请内存空间。但是这个系统函数调用后,os并不会立刻分配物理内存,而是等对申请到的内存块进行具体的读写之后再进行物理内存page实际分配。
测试代码
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main() {int test = 0;size_t initial_size = 1024*1024*50; // 初始大小为 50MBsize_t expanded_size = 1024*1024*512; // 扩展大小为 512MB// 创建映射区域void *ptr = mmap(NULL, initial_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);if (ptr == MAP_FAILED) {perror("mmap");exit(EXIT_FAILURE);}printf("Initial size: %zuKB\n", initial_size / 1024);scanf("%d", &test);// 使用 mremap 扩展映射区域的大小void *new_ptr = mremap(ptr, initial_size, expanded_size, MREMAP_MAYMOVE);if (new_ptr == MAP_FAILED) {perror("mremap");exit(EXIT_FAILURE);}printf("Expanded size: %zuKB\n", expanded_size / 1024);scanf("%d", &test);// 使用新的映射区域进行读写操作...//使用10Mmemset(new_ptr, 0, 1024 * 1024 * 10);scanf("%d", &test);// 使用100Mmemset(new_ptr, 0, 1024 * 1024 * 100);scanf("%d", &test);// 解除映射if (munmap(new_ptr, expanded_size) == -1) {perror("munmap");exit(EXIT_FAILURE);}return 0;
}
3.1 执行mmap函数
mmap函数执行后,查看top输出,虚拟内存52M接近申请的50M,而RES仅有1M

3.2 执行mremap
mremap执行后,查看top输出,虚拟内存涨到了514MB,接近扩容申请的512MB,RES常驻内存不变

3.3 执行第一个memset
接着执行第一个memset,进行内存写入。这次发现虚拟内存不变,而RES物理内存增长了10MB,这和memset的内存大小一致

3.4 执行第2个memset
接着执行第二个memset,写入100MB(指针位置没有变化)。虚存没有变化,RES增加了90MB。

使用pmp命令分析
lvsheng@lvsheng:/proc/36287$ pmap -x 41422
41422: ./mmap
Address Kbytes RSS Dirty Mode Mapping
0000c8e2d33a0000 4 4 0 r-x-- mmap
0000c8e2d33bf000 4 4 4 r---- mmap
0000c8e2d33c0000 4 4 4 rw--- mmap
0000c8e309014000 132 4 4 rw--- [ anon ]
0000e16bc8c00000 524288 102400 102400 rw--- [ anon ]
0000e16bebe20000 1640 1088 0 r-x-- libc.so.6
0000e16bebfba000 76 0 0 ----- libc.so.6
0000e16bebfcd000 12 12 12 r---- libc.so.6
0000e16bebfd0000 8 8 8 rw--- libc.so.6
0000e16bebfd2000 48 16 16 rw--- [ anon ]
0000e16bebfdf000 156 156 0 r-x-- ld-linux-aarch64.so.1
0000e16bec018000 8 8 8 rw--- [ anon ]
0000e16bec01a000 8 0 0 r---- [ anon ]
0000e16bec01c000 4 4 0 r-x-- [ anon ]
0000e16bec01d000 8 8 8 r---- ld-linux-aarch64.so.1
0000e16bec01f000 8 8 8 rw--- ld-linux-aarch64.so.1
0000fffff236c000 132 12 12 rw--- [ stack ]
---------------- ------- ------- -------
total kB 526540 103736 102484
512MB的虚拟内存,OS分配了100MB物理内存
四 总结

- jdk通过mmap申请内存后,操作系统分配的虚拟内存,并没有分配实际的物理内存。
- 当Java应用程序实际写入时,OS才会分配物理内存。
所以nmt和top的RES指标的差异会很明显
参考文章
- https://blog.csdn.net/qq_41687938/article/details/119901916
相关文章:
Native Memory Tracking 与 RSS的差异问题
一 问题现象 前一段时间用nmt查看jvm进程的栈区占用的内存大小。测试代码如下 public class ThreadOOM {public static void main(String[] args) {int i 1;while (i < 3000) {Thread thread new TestThread();thread.start();System.out.println("thread : "…...
完美世界前端面试题及参考答案
如何设置事件捕获和事件冒泡? 在 JavaScript 中,可以通过addEventListener方法来设置事件捕获和事件冒泡。该方法接收三个参数,第一个参数是事件类型,如click、mousedown等;第二个参数是事件处理函数;第三个参数是一个布尔值,用于指定是否使用事件捕获机制。当这个布尔值…...
知识库管理如何推动企业数字化转型与创新发展的深层次探索
内容概要 在当今数字化转型的大背景下,知识库管理日益显现出其作为企业创新发展的核心驱动力的潜力。这种管理方式不仅仅是对信息的存储与检索,更是一种赋能,以提升决策效率和员工创造力。企业能够通过系统地整合和管理各类知识资源…...
《DeepSeek 网页/API 性能异常(DeepSeek Web/API Degraded Performance):网络安全日志》
DeepSeek 网页/API 性能异常(DeepSeek Web/API Degraded Performance)订阅 已识别 - 已识别问题,并且正在实施修复。 1月 29, 2025 - 20:57 CST 更新 - 我们将继续监控任何其他问题。 1月 28, 2025 - 22&am…...
【性能优化专题系列】利用CompletableFuture优化多接口调用场景下的性能
背景说明 在实际的软件开发中,我们经常会遇到需要批量调用接口的场景。例如,电商系统在生成商品详情页时,需要同时调用多个服务接口来获取商品的基本信息、库存信息、价格信息、用户评价等。 传统的依次调用方式存在性能问题 面对上述场景…...
DeepSeek-R1本地部署笔记
文章目录 效果概要下载 ollama终端下载模型【可选】浏览器插件 UIQ: 内存占用高,显存占用不高,正常吗 效果 我的配置如下 E5 2666 V3 AMD 590Gme 可以说是慢的一批了,内存和显卡都太垃圾了,回去用我的新设备再试试 概要 安装…...
鸿蒙开发在onPageShow中数据加载不完整的问题分析与解决
API Version 12 1、onPageShow()作什么的 首先说明下几个前端接口的区别: ArkUI-X的aboutToAppear()接口是一个生命周期接口,用于在页面即将显示之前调用。 在ArkUI-X中,aboutToAppear()接口是一个重要的生命周期接口,它会在页…...
Kadane 算法
Kadane 算法 Kadane 算法用于解决最大子数组和问题,即在一个整数数组中找到具有最大和的连续子数组。此算法基于动态规划思想,在一次遍历过程中完成计算。 动态规划思路 核心在于维护两个变量:currentMax 表示当前子数组的最大和;globalMax 保存迄今为止发现的最大子数组…...
在Ubuntu子系统中基于Nginx部署Typecho
下载部署程序 typecho上传文件到子系统 创建文件夹typecho 在目录/var/www/html中创建一个目录typecho cd /var/www/html mkdir typecho将文件typecho.zip上传至新建的目录下,并解压文件 unzip typecho.zip授权文件夹 sudo chown -R www-data:www-data /var/www…...
C++中常用的十大排序方法之1——冒泡排序
成长路上不孤单😊😊😊😊😊😊 【😊///计算机爱好者😊///持续分享所学😊///如有需要欢迎收藏转发///😊】 今日分享关于C中常用的排序方法之——冒泡排序的相关…...
不只是mini-react第二节:实现最简fiber
省流|总结 首先,我们编写JSX文件,并通过Babel等转换工具将其转化为createElement()函数的调用,最终生成虚拟 DOM(Vdom)格式。举个例子: // 原始 JSX const App <div>hi-mini-react</div>;//…...
python 使用Whisper模型进行语音翻译
目录 一、Whisper 是什么? 二、Whisper 的基本命令行用法 三、代码实践 四、是否保留Token标记 五、翻译长度问题 六、性能分析 一、Whisper 是什么? Whisper 是由 OpenAI 开源的一个自动语音识别(Automatic Speech Recognition, ASR)系统。它的主要特点是: 多语言…...
priority_queue的创建_结构体类型(重载小于运算符)c++
当优先级队列里面存的是一个自定义(结构体)类型,我们有两种方式,一个是用内置类型的方式,在priority_queue<>里写三个参数,比如int, vector<int>, less<int>,把int改成结构体…...
数据结构实战之线性表(一)
一.线性表的定义和特点 线性表的定义 线性表是一种数据结构,它包含了一系列具有相同特性的数据元素,数据元素之间存在着顺序关系。例如,26个英文字母的字符表 ( (A, B, C, ....., Z) ) 就是一个线性表,其中每个字母就是一个数据…...
Python学习之旅:进阶阶段(七)数据结构-计数器(collections.Counter)
在 Python 编程的进阶学习中,数据处理是一项重要的任务。collections.Counter作为 Python 标准库collections模块中的一员,为我们提供了一种高效且便捷的方式来统计数据出现的次数。接下来,就让我们一起深入了解这个强大的计数器。 一、什么是计数器 collections.Counter本…...
Spring Boot项目如何使用MyBatis实现分页查询及其相关原理
写在前面:大家好!我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正,感谢大家的不吝赐教。我的唯一博客更新地址是:https://ac-fun.blog.csdn.net/。非常感谢大家的支持。一起加油,冲鸭&#x…...
【项目初始化】
项目初始化 使用脚手架创建项目Vite创建项目推荐拓展 使用脚手架创建项目 Vite Vite 是一个现代的前端构建工具,它提供了极速的更新和开发体验,支持多种前端框架,如 Vue、React 等创建项目 pnpm create vuelatest推荐拓展...
LeetCode热题100(八)—— 438.找到字符串中所有字母异位词
LeetCode热题100(八)—— 438.找到字符串中所有字母异位词 题目描述代码实现思路解析 你好,我是杨十一,一名热爱健身的程序员在Coding的征程中,不断探索与成长LeetCode热题100——刷题记录(不定期更新&…...
26.Word:创新产品展示说明会【9】
目录 NO1.2.3 NO4.5.6.7 NO1.2.3 另存为/F12:考生文件夹点亮显示和隐藏标记选中→插入→表格→文字转化成表格→✔制表符→确定布局→自动调整→设计→随便一种保存至“表格”部件库:选中表格→插入→文档部件→使用“表格”部件库:插入→…...
python 之 zip 和 * 解包操作
文章目录 1. zip 函数语法:示例:特点:应用场景: 2. * 操作符语法:示例:应用场景: 3. zip 和 * 的结合使用示例:转置二维列表 4. zip 和 * 的其他用法示例 1:合并多个列表…...
反向代理模块jmh
1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求,然后将请求转发给内部网络上的服务器,将从服务器上得到的结果返回给客户端,此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说,反向代理就相当…...
AI应用部署——streamlit
如何把项目部署到一个具有公网ip地址的服务器上,让他人看到? 可以利用 streamlit 的社区云免费部署 1、生成requirements.txt文件 终端输入pip freeze > requirements.txt即可 requirements.txt里既包括自己安装过的库,也包括这些库的…...
文明的基因:在传承中破茧重生
敦煌莫高窟的壁画历经千年风雨,至今仍在向世界讲述着东方美学的密码。那些斑驳的壁画上,既有北魏时期的天竺梵音,也留存着盛唐气象的长安余韵。文明的基因从未停止生长,就像莫高窟的壁画师们在临摹前朝壁画时,总会在衣…...
全国31省空间权重矩阵(地理相邻空间、公路铁路地理距离空间、经济空间)权重矩阵数据-社科数据
中国31个省份空间权重矩阵-社科数据https://download.csdn.net/download/paofuluolijiang/90028597 https://download.csdn.net/download/paofuluolijiang/90028597 空间权重矩阵是反映个体在空间中依赖关系的矩阵,本数据计算全国31个省三种标准化处理的空间权重矩…...
MySQL数据类型转换应注意什么?
文章目录 1. **隐式转换**2. **显式转换**3. **数据截断**4. **字符集与排序规则**5. **日期和时间转换**6. **数值转换**7. **NULL 处理**8. **性能影响**9. **错误处理**10. **函数选择**示例总结 在 MySQL 中进行数据类型转换时,需要注意以下几个关键点ÿ…...
前端开发之jsencrypt加密解密的使用方法和使用示例
目录 RSA密钥生成选项简介 jsencrypt 使用教程 一、安装 jsencrypt 二、使用 jsencrypt 进行加密和解密 1. 创建密钥对 2. 加密数据 3. 解密数据 三、实际应用示例 加密数据并存储到 localStorage 中: 从 localStorage 中读取加密数据并解密: …...
ESP32和STM32在处理中断方面的区别
为了通俗地讲解ESP32和STM32在处理中断方面的区别,我们可以把它们想象成两个不同的“智能管家”系统,各自负责管理一个家庭(即嵌入式项目)的各种任务。我们将重点放在如何处理突发事件(即中断)上。 ESP32 …...
98.1 AI量化开发:长文本AI金融智能体(Qwen-Long)对金融研报大批量处理与智能分析的实战应用
目录 0. 承前1. 简介1.1 通义千问(Qwen-Long)的长文本处理能力 2. 基础功能实现2.1 文件上传2.2 单文件分析2.3 多文件分析 3. 汇总代码&运行3.1 封装的工具函数3.2 主要功能特点3.3 使用示例3.4 首次运行3.5 运行结果展示 4. 注意事项4.1 文件要求4.2 错误处理机制4.3 最佳…...
PPT演示设置:插入音频同步切换播放时长计算
PPT中插入音频&同步切换&放时长计算 一、 插入音频及音频设置二、设置页面切换和音频同步三、播放时长计算 一、 插入音频及音频设置 1.插入音频:点击菜单栏插入-音频-选择PC上的音频(已存在的音频)或者录制音频(现场录制…...
链表的简单介绍
申明: 我们的链表可以写在类中或者接口中(接口中更好),这里我们是写在类当中。 1.节点的构造是由当前数据和指向下一个结点的地址组成,那么我们在当前这个链表的类中需要实现一个节点那么此时就需要用到内部类(当一个…...
