关于java内存管理的基础知识

原创 2013年03月31日 16:39:43

平常工作中,发现有蛮多日常细节与内存管理有关,一直想要停下来总结总结,未果。这两天和一朋友沟通时,虚拟地址与物理地址的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.进程和虚拟内存

现在都是64位OS,所以进程的虚拟寻址空间基本没有限制了;但是它mapping到的物理内存还是受限的。

虚拟内存一对多映射

进程的虚拟地址空间中的区域可被映射到物理内存、文件或任何其他可寻址存储。这里的区域也使用分页机制,当一个程序尝试使用虚拟地址访问内存时,操作系统连同硬件会将该分页的虚拟地址映射到物理位置,这个位置可以是物理RAM、一个文件或页面文件(交换分区)。

下面是从IBM网站找来的概要图,pagefile是windows的说法,对应linux下的swap。


图一:虚拟内存映射概要

上图中的进程可以是用户进程,也可以是内核进程(比如init fork出所有的进程)。用户进程的虚拟地址空间又有用户空间和内核空间(os空间)。每个进程都拥有自己的虚拟地址空间(逻辑地址区域)其大小由该系统上的地址大小规定。比如32位windows的单进程可寻址空间是4G,但是物理地址扩展后可能有64G。

思考四:我们开发中用的MappedByteBuffer其实说的通俗一点就是Map把文件的内容映像到计算机虚拟内存的一块区域,这样就可以直接操作内存当中的数据,而无需每次都通过I/O去物理硬盘读取文件,所以效率上有很大的提升。MappedByteBuffer主要使用场景有:需要用文件共享来实现进程间通信(使用同一个文件inode);需要写内存同时自动持久化到文件。


虚拟内存多对一映射

思考五:在图一中,虚拟内存地址可以指向同一个物理内存地址吗?一些嵌入式OS中,程序的确直接使用全部的物理内存;但是windows和linux是具有虚拟内存的操作系统,虚拟内存允许多个进程共享物理内存(比如OS只占用一段物理内存,但是每个进程都有内核地址空间,映射到同一段物理内存)。

尽管每个进程都有其自己的地址空间,但程序通常无法使用所有这些空间。地址空间被划分为内核空间和用户空间。大部分操作系统将每个进程地址空间的一部分映射到一个通用的内核内存区域。被映射来供内核使用的地址空间部分称为内核空间,其余部分称为用户空间,可供用户应用程序使用。

在思考二中,物理内存被用于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大小,用来解决内存碎片、快取、文件转内存等问题。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Java学习笔记-《Java程序员面试宝典》-第四章基础知识-4.8 Java平台与内存管理(4.8.1-4.8.3)

4.8.1为什么说Java是平台独立性语言平台独立性是指可以在一个平台上编写和编译程序,而在其他平台上运行。保证Java具有平台独立性的机制为”中间码”和”Java虚拟机(JVM)”。Java程序被贬...

人物专访:核心黑客系列之一 Robert Love

Java 基础知识总结之平台与内存管理(二)

继上次写过一些基本知识点后,今天继续来学习 Java 中的知识点,主要介绍 Java 平台与内存管理,首先来看今天知识点的概览 一、Java 为什么是平台独立性语言        平台独立性是...

Java学习笔记-《Java程序员面试宝典》-第四章基础知识-4.8 Java平台与内存管理(4.8.4-4.8.6)

4.8.4 什么是GC在Java语言中,垃圾回收(Garbage Collection,GC)的主要作用是回收程序中不再使用的内存。为了减轻开发人员的工作,同时增加系统的安全性和稳定性,Java语言提...

虚拟内存管理基础知识

  • 2008年09月26日 15:29
  • 254KB
  • 下载

c++核心基础知识(内存管理)

内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不在,内存泄...

Objective-C 基础知识之 (十六):内存管理原则一

内存管理   OC中的内存管理机制:引用计数 每个对象都有引用计数。理论上:当对象的引用计数为0时,系统会自动调用方法,销毁对象,回收内存。 在开发中,存在多个指针操作同一个对象。如果需要使用...

OC基础知识 -- 内存管理

内存管理内存管理的三种方式1.垃圾回收(gc)轮询延迟 程序员只需要开辟内存空间,不需要⽤代码显⽰地释放,系统来判断哪些空间不再被使⽤,并回收这些内存空间,以便再次分配。整个回收的过程不需要写任何...

ios 内存管理基础知识

先简单解释一下nil和release的作用:nil就是把一个对象的指针置为空,只是切断了指针与内存中对象的联系;而release才是真正通知内存释放这个对象。所以nil并没有释放内存,只有releas...

C语言内存管理基础知识总结

《一》:内存的分配 内存分配一般是有五种方式:静态存储区域分配、堆区、栈区、常量区、代码区; 静态存储区域一般对应的是整个程序运行期间都一直存在,内存在编译的时候就已经分配好了,常见的全局变量,静态变...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:关于java内存管理的基础知识
举报原因:
原因补充:

(最多只允许输入30个字)