Linux和进程内存模型

1、Linux和进程内存模型linux

jvm是一个进程的身份运行在linux系统上,了解linux和进程的内存关系,是理解jvm和Linux内存关系的基础。程序员

硬件、系统、进程三个层面的内存之间的概要关系数据结构

一、从硬件上看,linux系统有两部分组成:物理内存和SWAP(位于磁盘),物理内存是linux活动时使用的主要内存区域,当物理内存不够使用时,linux会把一部分暂时不用的内存数据放在SWAP中,以便腾出更多的可用内存空间;而当须要使用位于SWAP的数据时,必须先将其换回到内存中。app

二、从linux系统上看,除了引导系统的BIN区,整个内存空间主要被分为两个部分:内核内存(Kernel space)、用户内存(user space)。异步

内核内存是linux自身使用的内存空间,主要提供给程序调度、内存分配、链接硬件资源等程序逻辑使用。用户内存是提供各个进程主要空间,Linux给各个进程提供相同的虚拟内存空间;这使的进程之间相互独立、互不干扰。实现的方法是采用虚拟内存技术:给每一个进程分配必定的虚拟内存,若是虚拟内存使用完了,才分配物理内存,对于32的Linux系统来讲,通常将0~3G的虚拟内存空间分配作为用户空间,将3~4G的虚拟内存空间分配为内核空间;64位系统的划分状况是相似的。jvm

三、从进程的角度来看,进程能直接访问的用户内存(虚拟内存空间)被划分为5个部分:代码区、数据区、堆区、栈区、未使用区。函数

代码区主要存放应用程序的机器代码,运行过程当中代码不能被修改,具备只读和固定大小的特色。性能

数据区存放了应用程序中的全局数据、静态数据和一些常量字符串等,该区大小也是固定的。spa

堆是运行时程序动态申请的空间,属于程序运行时直接申请、释放的内存资源。操作系统

栈区用来存放函数的传入参数、临时变量,以及返回地址等数据。

未使用区是分配新内存空间的预备区域。

2、进程和jvm内存模型

JVM本质就是一个进程,所以其内存模型也有进程的通常特色。可是,JVM又不是一个普通的进程,其在内存模型上有许多崭新的特色,主要缘由有两个:1.JVM将许多原本属于操做系统管理范畴的东西,移植到了JVM内部,目的在于减小系统调用的次数;2. Java NIO,目的在于减小用于读写IO的系统调用的开销,JVM进程与普通进程内存模型比较以下图:

一、用户内存

上图特别强调了JVM进程模型的代码区和数据区指的是JVM自身的,而非Java程序的。普通进程栈区,在JVM通常仅仅用作线程栈。JVM的堆区和普通进程的差异是最大的,下面具体详细说明:

首先是永久代。永久代本质上是Java程序的代码区和数据区。Java程序中类(class),会被加载到整个区域的不一样数据结构中去,包括常量池、域、方法数据、方法体、构造函数、以及类中的专用方法、实例初始化、接口初始化等。这个区域对于操做系统来讲,是堆的一个部分;而对于Java程序来讲,这是容纳程序自己及静态资源的空间,使得JVM可以解释执行Java程序。

其次是新生代和老年代。新生代和老年代才是Java程序真正使用的堆空间,主要用于内存对象的存储;可是其管理方式和普通进程有本质的区别。
普通进程在运行时给内存对象分配空间时,好比C++执行new操做时,会触发一次分配内存空间的系统调用,由操做系统的线程根据对象的大小分配好空间后返回;同时,程序释放对象时,好比C++执行delete操做时,也会触发一次系统调用,通知操做系统对象所占用的空间已经能够回收。
JVM对内存的使用和通常进程不一样。JVM向操做系统申请一整段内存区域(具体大小能够在JVM参数调节)做为Java程序的堆(分为新生代和老年代);当Java程序申请内存空间,好比执行new操做,JVM将在这段空间中按所需大小分配给Java程序,而且Java程序不负责通知JVM什么时候能够释放这个对象的空间,垃圾对象内存空间的回收由JVM进行。

JVM的内存管理方式的优势是显而易见的,包括:第一,减小系统调用的次数,JVM在给Java程序分配内存空间时不须要操做系统干预,仅仅在Java堆大小变化时须要向操做系统申请内存或通知回收,而普通程序每次内存空间的分配回收都须要系统调用参与;第二,减小内存泄漏,普通程序没有(或者没有及时)通知操做系统内存空间的释放是内存泄漏的重要缘由之一,而由JVM统一管理,能够避免程序员带来的内存泄漏问题。

最后是未使用区,未使用区是分配新内存空间的预备区域。对于普通进程来讲,这个区域被可用于堆和栈空间的申请及释放,每次堆内存分配都会使用这个区域,所以大小变更频繁;对于JVM进程来讲,调整堆大小及线程栈时会使用该区域,而堆大小通常较少调整,所以大小相对稳定。操做系统会动态调整这个区域的大小,而且这个区域一般并无被分配实际的物理内存,只是容许进程在这个区域申请堆或栈空间。

二、内核内存

应用程序一般不直接和内核内存打交道,内核内存由操做系统进行管理和使用;不过随着Linux对性能的关注及改进,一些新的特性使得应用程序可使用内核内存,或者是映射到内核空间。Java NIO正是在这种背景下诞生的,其充分利用了Linux系统的新特性,提高了Java程序的IO性能。

上图给出了Java NIO使用的内核内存在linux系统中的分布状况。nio buffer主要包括:nio使用各类channel时所使用的ByteBuffer、Java程序主动使用ByteBuffer.allocateDirector申请分配的Buffer。而在PageCache里面,nio使用的内存主要包括:FileChannel.map方式打开文件占用mapped、FileChannel.transferTo和FileChannel.transferFrom所须要的Cache(图中标示 nio file)。

经过JMX能够监控到NIO Buffer和 mapped 的使用状况,以下图所示。不过,FileChannel的实现是经过系统调用使用原生的PageCache,过程对于Java是透明的,没法监控到这部份内存的使用大小。

Linux和Java NIO在内核内存上开辟空间给程序使用,主要是减小不要的复制,以减小IO操做系统调用的开销。例如,将磁盘文件的数据发送网卡,使用普通方法和NIO时,数据流动比较下图所示:

将数据在内核内存和用户内存之间拷贝是比较消耗资源和时间的事情,而从上图咱们能够看到,经过NIO的方式减小了2次内核内存和用户内存之间的数据拷贝。这是Java NIO高性能的重要机制之一(另外一个是异步非阻塞)。

从上面能够看出,内核内存对于Java程序性能也很是重要,所以,在划分系统内存使用时候,必定要给内核留出必定可用空间。

相关文章
相关标签/搜索