深圳尚学堂:关于java内存管理的基础知识
ahcoder 2025-06-23 14:25 1 浏览
平常工作中,发现有蛮多日常细节与内存管理有关,一直想要停下来总结总结,未果。这两天和一朋友沟通时,虚拟地址与物理地址的mapping方式这个问题,让平常一直考虑的关于top、mmap、ringbuffer、DirectByteBuffer等细节点在脑海中翻腾,竟然一时语塞。所以今天在家写了点测试代码,让自己把思路理顺,整理出来,希望这些基础知识对大家有用。
1.硬件层面和物理内存
物理内存概要
大家都知道,物理内存就是RAM。处理器通过内存总线连接到物理内存,总线位数(比如32位或者48位)决定了可寻址的物理内存大小。这里提到48位这个值,是提醒不要与CPU的寄存器带宽混淆。X86_64的寄存器带宽是64,但是物理地址位数可能是48。(物理地址扩展后,物理地址位数也可能大于寄存器带宽)。
物理内存分页寻址,每页4K。对于32位的地址,第0页从0x00000000到0x00001000。可以看到,只需要前20位用来寻址物理页,而后12位用来标示页内地址。
思考一:这样内存分页使用有什么优点呢?在本文最后讲到ringbuffer时会分析这个问题。
物理内存和磁盘的互惠交易
在linux协调下,物理内存和磁盘间有“最惠国待遇条约”:
1) 物理内存充裕时:
linux会把一些物理内存用于io的buffer及cache,提升系统运行效率。
Linux下的sar -r命令结果中,总体可用的物理内存应该为:kbmemfree+kbbuffers+kbcached。
思考二:这里使用的物理内存,它所mapping到的虚存会归属什么进程呢?后面会有讨论。
2) 物理内存不够时:
linux会把物理内存的一部分数据放入磁盘swap区存储,以腾出内存给程序使用。
Vmstat命令结果中,swap下的si是每秒从磁盘读到内存的数据量,so是从内存写到磁盘的数据量。
创建Swap时(mkswap命令)可以用swap分区,也可以用普通文件。我实验了一下,用swap分区方式,在swapon /dev/hdc7后,used、free、buffer、cache内存都有增长;而用文件方式,这四个量都不变。
思考三:这里说的把文件映射到物理内存,与下文提到的MappedByteBuffer映射到虚拟内存场景是不一样的。
2.操作系统和虚拟内存
虚拟内存一对多映射
进程的虚拟地址空间中的区域可被映射到物理内存、文件或任何其他可寻址存储。这里的区域也使用分页机制,当一个程序尝试使用虚拟地址访问内存时,操作系统连同硬件会将该分页的虚拟地址映射到物理位置,这个位置可以是物理RAM、一个文件或页面文件(交换分区)。
思考四:我们开发中用的MappedByteBuffer其实说的通俗一点就是Map把文件的内容映像到计算机虚拟内存的一块区域,这样就可以直接操作内存当中的数据,而无需每次都通过I/O去物理硬盘读取文件,所以效率上有很大的提升。MappedByteBuffer主要使用场景有:需要用文件共享来实现进程间通信(使用同一个文件inode);需要写内存同时自动持久化到文件。
虚拟内存多对一映射
思考五:在图一中,虚拟内存地址可以指向同一个物理内存地址吗?一些嵌入式OS中,程序的确直接使用全部的物理内存;但是windows和linux是具有虚拟内存的操作系统,虚拟内存允许多个进程共享物理内存。
尽管每个进程都有其自己的地址空间,但程序通常无法使用所有这些空间。地址空间被划分为内核空间和用户空间。大部分操作系统将每个进程地址空间的一部分映射到一个通用的内核内存区域。被映射来供内核使用的地址空间部分称为内核空间,其余部分称为用户空间,可供用户应用程序使用。
在思考二中,物理内存被用于buffer与cache,大都是内核空间的行为。默认情况下,32 位 Windows 拥有 2GB 用户空间和 2GB 内核空间;而linux分别是3G和1G。
内核是主要的操作系统程序,包含用于连接计算机硬件、调度程序以及提供联网和虚拟内存等服务的逻辑。作为计算机启动序列的一部分,操作系统内核运行并初始化硬件。
如果用户程序需要来自操作系统的服务,它可以执行一种称为系统调用的操作与内核程序交互。系统调用通常是读取和写入文件、联网和启动新进程等操作所必需的。Mmap系统调用实现时
3 Java进程使用的内存
在 Linux 和 Windows 上,进程是一个由受操作系统控制的资源(比如文件和套接字信息)、一个典型的虚拟地址空间(在某些架构上不止一个)和至少一个执行线程构成的集合。
Java是单进程应用,和普通进程没有本质区别。
有了上面的分析,可以很容易明白为什么我们用top看到的java进程消耗的内存有时候会大于-Xmx 与-XX:MaxPermSize的和。java进程消费的内存包括JVM内存和java应用消费的JVM之外的物理内存,我们一般情况下不能用top来判断多少是JVM消耗的、多少是JVM外的内存。
Java进程使用的内存一般有如下这些:
1) java堆和永久代。
2) 线程堆栈。-Xss可以调整,栈深度不够时抛出StackOverflowException,无内存可以分配于新线程创建时抛出OutOfMemoryError。
3) JIT编译、JNI代码、GC。
4) Socket缓冲区。每个Socket连接的Receive缓存区约37KB,Send缓存区约25KB,在连接数多的情况下也是很可观的。
5) DirectMemory。平常开发用的一些框架(比如CometD),会有大量的NIO操作使用到DirectByteBuffer,它通过native库直接分配堆外内存,这里使用的空间也在虚拟内存地址范围内,受进程可访问空间的限制,也可能导致OutofMemoryError。
写了一个简单的程序来测试DirectByteBuffer对top和jstat的结果的影响:
1) DirectByteBuffer在堆中的引用清空后,gc,也可以释放堆外物理内存。
2) 程序启动时,-Xms的空间只是被分配地址空间,top不计入使用的内存。
3) 使用过内存后,即使堆内存GC,还是会计入使用的内存。这个可能与新生代使用“复制算法”而不是“标记-整理算法”来实现GC有关系。
4 分页机制与ringbuffer
Ringbuffer也使用了mmap技术,但是这里我们要讨论的是思考一中的问题:它借鉴内存分页技术,可以用来做什么?
前面的4K分页技术,可以前20位用来寻址物理页,而后12位用来标示页内地址;其实可以再演化,比如用前10位表示第几个4M的文件,后22位表示是4M文件中的第几个。这样可以在Ringbuff中设置不同的slot大小,用来解决内存碎片、快取、文件转内存等问题。
相关推荐
- Linux 下如何查看进程的资源限制信息?
-
简介Linux上的cat/proc/$pid/limits命令提供有关特定进程的资源限制的信息,其中$pid是相关进程的进程ID(pid)。该文件是`/proc文件系统的一部分,该...
- Linux入侵排查TOP10误区!90%工程师都踩过坑
-
导语“删除恶意文件却破坏了关键证据”“盲目重启系统导致攻击链中断”——这些看似合理的操作,可能让入侵排查陷入僵局。据统计,全球90%的Linux工程师在首次应对入侵事件时至少踩中3个排查误区。本文深度...
- 一文掌握怎么利用Shell脚本实现Linux系统资源监控管理程序
-
简介:在日常管理Linux服务器时,监控和管理系统资源是确保服务器稳定运行的关键。及时了解CPU、内存、硬盘以及网络的使用情况,可以帮助我们预防系统故障,并找出性能上的瓶颈。虽然有很多专业的监控工具,...
- Linux 下的 PM2 完整指南(linuxnmcli)
-
PM2是Node.js应用的专业级进程管理器,专为生产环境设计,提供应用守护、集群管理、日志监控等核心功能。核心特性应用守护:崩溃时自动重启零秒重载:热更新应用不停机(pm2reload)...
- linux中磁盘满了?一招教你快速清理
-
创作背景:当天部署服务时,发现无法部署,后来经过日志排查后发现服务器磁盘满了,查询资料后进行了清理。话不多说,直接上解决方法。操作一:1.查看磁盘大小:df-h2.直接在最上层进行排序:du-a...
- 适用于 Linux 的内存分析器:Bytehound
-
#暑期创作大赛#特征可用于分析内存泄漏,查看内存到底在哪里被消耗,识别临时分配并调查过多的内存碎片收集每次分配和释放以及完整的堆栈跟踪可以动态剔除临时分配,使您能够在很长一段时间内进行分析使用定制的堆...
- 一文讲清Python在Linux系统CPU、内存和磁盘管理方面的应用实例
-
摘要:在当今快速发展的IT运维和开发世界里,Linux系统凭借其高效能、高稳定性和开源的特性,在服务器管理、云计算服务以及大数据处理等众多领域中占据了核心位置。随着业务规模扩大,系统资源的监控与管理变...
- Linux系统磁盘分区管理LVM概念及扩容操作
-
LVM的全称为LogicalVolumeManager,逻辑卷管理。它是Linux环境下对磁盘分区进行管理的一种机制,LVM是建立在硬盘和分区之上的一个逻辑层,来提高磁盘分区管理的灵活性。通过L...
- ringbuffer 消息队列 内存池 性能优化利器
-
简约而不简单的ringbuffer最近在研究srsLTE的代码,其中就发现一个有意思的数据结构------ringbuffer。虽然,这是一个很基本的数据结构,但时,它在LTE这种通信协议栈系统中却大...
- Rocky Linux 9常用命令备忘录(不定时更新)
-
RockyLinux9常用命令备忘录(不定时更新)大家好,我是星哥,上次介绍了<RockyLinux9系统安装配置图解教程并做简单配置>:https://mp.weixin.qq...
- 理解Linux的Memory overcommit(linux reserved-memory)
-
MemoryOvercommit的意思是操作系统承诺给进程的内存大小超过了实际可用的内存。一个保守的操作系统不会允许memoryovercommit,有多少就分配多少,再申请就没有了,这其实有些浪...
- Linux systemd 4 命令深度对比:休眠、睡眠、关
-
"90%的人不知道Linux关机命令暗藏玄机?三招教你选对保命符"键盘突然没反应?电脑卡成PPT?这些崩溃瞬间可能都怪你选错了系统命令!今天就用咖啡厅偶遇的工程师视角,带你看懂Linu...
- 一次解决Linux内核内存泄漏实战全过程
-
什么是内存泄漏:程序向系统申请内存,使用完不需要之后,不释放内存还给系统回收,造成申请的内存被浪费.发现系统中内存使用量随着时间的流逝,消耗的越来越多,例如下图所示:接下来的排查思路是:1.监控系统中...
- Linux系列:聊一聊 SystemV 下的进程间共享内存
-
一:背景1.讲故事昨天在分析一个linux的dump时,看到了这么一话警告,参考如下:0:000>!eeheap-gc***WARNING:Unabletoverifyt...
- linux收发网络包过程(linux收包流程)
-
网络模型由于OSI模型实在太复杂,提出的也只是概念理论上的分层,并没有提供具体的实现方案事实上,我们比较常,也比较实用的是四层模型,即TCP/IP网络模型,Linux系统正是按照这套网络模型...
- 一周热门
- 最近发表
- 标签列表
-
- linux 远程 (37)
- u盘 linux (32)
- linux 登录 (34)
- linux 路径 (33)
- linux 文件命令 (35)
- linux 是什么 (35)
- linux 界面 (34)
- 查看文件 linux (35)
- linux 语言 (33)
- linux代码 (32)
- linux 查看命令 (33)
- 关闭linux (34)
- root linux (33)
- 删除文件 linux (35)
- linux 主机 (34)
- linux与 (33)
- linux 函数 (35)
- linux .ssh (35)
- cpu linux (35)
- 查看linux 系统 (32)
- linux 防火墙 (33)
- linux 手机 (32)
- linux 镜像 (34)
- linux ip地址 (34)
- linux 用户查看 (33)