当前位置: 首页 > news >正文

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物理内存

四 总结

在这里插入图片描述

  1. jdk通过mmap申请内存后,操作系统分配的虚拟内存,并没有分配实际的物理内存。
  2. 当Java应用程序实际写入时,OS才会分配物理内存。

所以nmt和top的RES指标的差异会很明显

参考文章


  1. 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 : "…...

在K8s中部署动态nfs存储provisioner

背景 之前&#xff0c;我已经在一台worker node上安装了local lvm 的provisioner来模拟需要本地高IOPS的数据库等stafeful应用的实现。 为了后续给虚拟机里的K8s集群安装可用的metrics和logs监控系统&#xff08;metrics和logs的时序数据库需要永久存储&#xff09;&#xff0…...

家庭财务管理系统的设计与实现

标题:家庭财务管理系统的设计与实现 内容:1.摘要 摘要&#xff1a;随着家庭经济的日益复杂&#xff0c;家庭财务管理变得越来越重要。本文旨在设计并实现一个功能强大的家庭财务管理系统&#xff0c;以帮助用户更好地管理家庭财务。通过对家庭财务管理需求的分析&#xff0c;我…...

数据结构-Stack和栈

1.栈 1.1什么是栈 栈是一种特殊的线性表&#xff0c;只允许在固定的一段进行插入和删除操作&#xff0c;进行插入和删除操作的一段称为栈顶&#xff0c;另一端称为栈底。 栈中的数据元素遵顼后进先出LIFO&#xff08;Last In First Out&#xff09;的原则&#xff0c;就像一…...

使用vhd虚拟磁盘安装两个win10系统

使用vhd虚拟磁盘安装两个win10系统 前言vhd虚拟磁盘技术简介准备工具开始动手实践1.winX选择磁盘管理2.选择“操作”--“创建VHD”3.自定义一个位置&#xff0c;输入虚拟磁盘大小4.右键初始化磁盘5.选择GPT分区表格式6.右键新建简单卷7.给卷起个名字&#xff0c;用于区分8.打开…...

代码随想录34 动态规划

1.经典问题&#xff1a; 背包问题 打家劫舍 斐波那契数列 爬楼梯问题 股票问题 2.dp数组以及下标的含义 3.递推公式 3.dp数组初始化 4.遍历顺序 5.打印数组 leetcode509.斐波那契数列 1.确定dp[i]含义 dp[i]第i个斐波那契数的值为dp[i] 2.递推公式&#xff1a;dp[…...

【2025年最新版】Java JDK安装、环境配置教程 (图文非常详细)

文章目录 【2025年最新版】Java JDK安装、环境配置教程 &#xff08;图文非常详细&#xff09;1. JDK介绍2. 下载 JDK3. 安装 JDK4. 配置环境变量5. 验证安装6. 创建并测试简单的 Java 程序6.1 创建 Java 程序&#xff1a;6.2 编译和运行程序&#xff1a;6.3 在显示或更改文件的…...

Shell特殊状态变量以及常用内置变量总结

目录 1. 特殊的状态变量 1.1 $?&#xff08;上一个命令的退出状态&#xff09; 1.2 $$&#xff08;当前进程的 PID&#xff09; 1.3 $!&#xff08;后台进程的 PID&#xff09; 1.4 $_&#xff08;上一条命令的最后一个参数&#xff09; 2.常用shell内置变量 2.1 echo&…...

【4Day创客实践入门教程】Day4 迈向高手之路——进一步学习!

Day4 迈向高手之路——进一步学习&#xff01; 目录 Day4 迈向高手之路——进一步学习&#xff01;更多的开发板外壳制作 Day0 创想启程——课程与项目预览Day1 工具箱构建——开发环境的构建Day2 探秘微控制器——单片机与MicroPython初步Day3 实战演练——桌面迷你番茄钟Day4…...

EtherCAT-快速搭建

EtherCAT-快速搭建 快速简介 快速简介 EtherCAT现场总线协议是由德国倍福公司在2003年提出的&#xff0c;该通讯协议拓扑结构十分灵活&#xff0c;数据传输速度快&#xff0c;同步特性好&#xff0c;可以形成各种网络拓扑结构。倍福公司推出了自己的ASIC专用芯片有ET1100和ET1…...

【设计测试用例自动化测试性能测试 实战篇】

&#x1f308;个人主页&#xff1a;努力学编程’ ⛅个人推荐&#xff1a; c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构&#xff0c;刷题刻不容缓&#xff1a;点击一起刷题 &#x1f319;心灵鸡汤&#xff1a;总有人要赢&#xff0c;为什么不能是我呢 设计测试用例…...

DBeaver连接MySQL提示Access denied for user ‘‘@‘ip‘ (using password: YES)的解决方法

在使用DBeaver连接MySQL数据库时&#xff0c;如果遇到“Access denied for user ip (using password: YES)”的错误提示&#xff0c;说明用户认证失败。此问题通常与数据库用户权限、配置错误或网络设置有关。本文将详细介绍解决此问题的步骤。 一、检查用户名和密码 首先&am…...

【MySQL — 数据库增删改查操作】深入解析MySQL的 Update 和 Delete 操作

1. 测试数据 mysql> select* from exam1; ----------------------------------------- | id | name | Chinese | Math | English | ----------------------------------------- | 1 | 唐三藏 | 67.0 | 98.0 | 56.0 | | 2 | 孙悟空 | 87.0 | 78.…...

04树 + 堆 + 优先队列 + 图(D1_树(D1_基本介绍))

目录 一、什么是树&#xff1f; 二、相关术语 根结点 边 叶子结点 兄弟结点 祖先结点 结点的大小 树的层 结点的深度 结点的高度 树的高度 斜树 一、什么是树&#xff1f; 树是一种类似于链表的数据结构&#xff0c;不过链表的结点是以线性方式简单地指向其后继结…...

【Proteus仿真】【51单片机】多功能计算器系统设计

目录 一、主要功能 二、使用步骤 三、硬件资源 四、软件设计 五、实验现象 联系作者 一、主要功能 1、LCD1602液晶显示 2、矩阵按键​ 3、加减乘除&#xff0c;开方运算 4、带符号运算 5、最大 999*999 二、使用步骤 基于51单片机多功能计算器 包含&#xff1a;程序&…...

Solon Cloud Gateway 开发:Route 的配置与注册方式

路由的配置与注册有三种方式&#xff1a;手动配置&#xff1b;自动发现配置&#xff1b;代码注册。 1、手动配置方式 solon.cloud.gateway:routes: #!必选- id: demotarget: "http://localhost:8080" # 或 "lb://user-service"predicates: #?可选- &quo…...

jstat命令详解

jstat 用于监视虚拟机运行时状态信息的命令&#xff0c;它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据。 命令的使用格式如下。 jstat [option] LVMID [interval] [count]各个参数详解&#xff1a; option&#xff1a;操作参数LVMID&#xff1a;本…...

[Collection与数据结构] B树与B+树

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…...

Ubuntu 24.04 安装 NVIDIA Container Toolkit 全指南:让Docker拥抱GPU

Ubuntu 24.04 安装 NVIDIA Container Toolkit 全指南&#xff1a;让Docker拥抱GPU 前言一、环境准备1.1 验证驱动状态 二、安装NVIDIA Container Toolkit2.1 添加官方仓库2.2 执行安装 三、配置Docker运行时3.1 更新Docker配置 四、验证安装结果4.1 运行测试容器 五、实战应用 …...

17.Word:李楠-学术期刊❗【29】

目录 题目​ NO1.2.3.4.5 NO6.7.8 NO9.10.11 NO12.13.14.15 NO16 题目 NO1.2.3.4.5 另存为手动/F12Fn光标来到开头位置处→插入→封面→选择花丝→根据样例图片&#xff0c;对应位置填入对应文字 (手动调整即可&#xff09;复制样式&#xff1a;开始→样式对话框→管理…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...