本文转载自美团技术团队发表的同名文章

https://tech.meituan.com/linux-jvm-memory.html

一, linux与进程内存模型

要理解jvm最重要的一点是要知道jvm只是linux的一个进程,把jvm的视野放大,就能很好的理解JVM细分的一些概念

下图给出了硬件系统进程三个层面内存之间的关系.

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

从Linux系统上看,除了引导系统的BIN区,整个内存空间主要被分成两个部分:内核内存(Kernel space)、用户内存(User space)。

内核内存是linux自身使用的内存空间,主要提供程序调度,内存分配,链接硬件资源等程序逻辑使用.用户内存是提供给各个进程主要空间,linux给每个进程提供4G相同的虚拟内存空间;这种虚拟内存空间,是一种寻址的空间,进程之间都有相互独立的4G空间地址,实际用到多少,最终会通过页表写入真正的磁盘.因此进程之间也是相互独立的,互不干扰

虚拟内存空间分配如下,

从进程角度看进程能直接访问的用户内存被划分为五个部分(与jvm的内存划分类似,因为它也是linux的一个进程):代码区,数据区,堆区,栈区,未使用区,

代码区中存放应用程序的机器代码,运行过程中代码不能被修改,具有只读和固定大小的特点

数据区中存放应用程序的机器代码静态数据和一些常量字符串等,其大小也是固定的,

堆是运行时程序动态申请的空间,属于程序运行时直接申请释放的内存资源(jvm的GC也主要回收该部分空间)

栈区用来存放函数的传入参数,临时变量(jvm中的方法使用的栈帧),以及返回地址等数据,

二,进程与jvm内存模型

jvm本质是一个进程,因此其内部也有进程的一般特点,但是jvm不是一个普通的进程,其内存模型有一些新特点:1,jvm将许多本来属于操作系统管理范畴的东西,移植到了jvm内部,目的在于减少系统调用的次数;2,JavaNIO,目的在于减少用于读写IO的系统调用的销,jvm进程与普通进程内存模型比较图:

需要说明的是,这个模型的并不是JVM内存使用的精确模型,更侧重于从操作系统的角度而省略了一些JVM的内部细节(尽管也很重要)。下面从用户内存和内核内存两个方面讲解JVM进程的内存特点。

1,用户内存

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

首先是永久代,永久代本质上是Java程序的代码区和数据区,Java程序中类(class),会被加载整个区域的不同数据结构中去,包括常量池,域,方法数据,方法体,构造函数,以及类中的专用方法,实例初始化,接口初始化.永久代对于操作系统来说是堆的一部分;而对于Java程序来说,这是容纳程序本身及静态资源的空间

其次是新生代和老年代,新生代和老年代才是Java程序真正使用的堆空间,主要用于内存对象的存储;但是其管理方式和普通进程有本质的区别。

普通进程在运行时给内存对象分配空间时,比如C++执行new操作时,会触发一次分配内存空间的调用,由操作系统的线程根据对象的大小分配好空间后返回;同时程序释放对象时,比如c++执行delete操作时也会触发一次系统调用,通知操作系统对象所占用的空间可以回收了

jvm对于内存的使用和一般进程不同,jvm像操作系统申请一整段内存区域(具体大小可以在jvm参数调节)作为Java内存的堆(分为新生代和老年代);当Java程序申请内存空间,比如new操作时,jvm将在这段空间中按所需大小分配给Java程序,并且Java不负责通知回收该内存空间.

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

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

2.内核内存

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

上图给出了NIO使用的内核内存在linux系统中的分布情况,NIObuffer主要包括:NIO使用各种channel时所使用的ByteBuffer,Java程序主动使用ByteBuffer,allocationDirector申请分配的Buffer.而在PageCache里面,NIO使用的内存主要包括FileChannel.map方式打开文件占用mapped,FileChanneltransferTo和FileChannel.transferFRrom

Linux和JavaNIO在内核内存上开辟空间给程序使用,主要是减少不必要的复制,减少IO操作系统调用的开销.例如将磁盘文件数据发送到网卡,使用普通方法和NIO时,数据流动比较

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

从上面可以看出,内核内存对于Java程序性能也非常重要,因此,在划分系统内存使用时候,一定要给内核留出一定可用空间。

https://mp.weixin.qq.com/s?__biz=MzI4NTEzMjc5Mw==&mid=2650554698&idx=1&sn=7f08e278c1f6a7c0db0ba5418c442fa4&chksm=f3f833dcc48fbacaede8af14925b983f871e834e58ba079c3cb41557bd5fa5596817fcab1543#rd

深入理解java虚拟机(linux与jvm内存关系)的更多相关文章

  1. 《深入理解 Java 虚拟机》学习笔记 -- 内存区域

    <深入理解 Java 虚拟机>学习笔记 -- 内存区域 运行时数据区域 主要分为 6 部分: 程序计数器 虚拟机栈 本地方法栈 Java 堆 方法区 如图所示: 1. 程序计数器(线程私有 ...

  2. 深入理解java虚拟机(6)---内存模型与线程 & Volatile

    其实关于线程的使用,之前已经写过博客讲解过这部分的内容: http://www.cnblogs.com/deman/category/621531.html JVM里面关于多线程的部分,主要是多线程是 ...

  3. 深入理解java虚拟机(1)------内存区域与内存溢出

    在C++领域,关于C++的内存存储,结构等等,有一本书:深度探索C++对象模型,讲解的非常透彻. 而Java确把这一工作交给了虚拟机来处理. 我们首先来看看关于内存的问题. 1.问题: 1)java ...

  4. 深入理解java虚拟机----->垃圾收集器与内存分配策略(下)

    1.  前言 内存分配与回收策略 JVM堆的结构分析(新生代.老年代.永久代) 对象优先在Eden分配 大对象直接进入老年代 长期存活的对象将进入老年代 动态对象年龄判定 空间分配担保  2.  垃圾 ...

  5. Java虚拟机详解----JVM内存结构

    http://www.cnblogs.com/smyhvae/p/4748392.htm 主要内容如下: JVM启动流程 JVM基本结构 内存模型 编译和解释运行的概念 一.JVM启动流程: JVM启 ...

  6. 深入理解java虚拟机(1)走进jvm

    1.JDK:java程序设计语言.java虚拟机.javaAPI 二.自动内存管理机制 ----------------------------------------------------- 1. ...

  7. 【深入理解JAVA虚拟机】第二部分.内存自动管理机制.1.内存区域

    1.内存区域 根据<Java虚拟机规范(Java SE 7版)> 的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域,如图所示.  程序计数器 当前线程所执行的字节码的行号指 ...

  8. 深入理解java虚拟机读书笔记1--java内存区域

    Java在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途.创建和销毁的时间,有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,有些则是与线程一一对应,随 ...

  9. 深入理解Java虚拟机读书笔记8----Java内存模型与线程

    八 Java内存模型与线程   1 Java内存模型     ---主要目标:定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节.     ---此处的变量和J ...

随机推荐

  1. 生命游戏(python实现,pygame显示图形)

    # 游戏规则:# 生命游戏(Game of Life),或者叫它的全称John Conway's Game of Life.是英国数学家约翰·康威在1970年代所发明的一种元胞自动机.# 1. 活细胞 ...

  2. jstree:重新加载数据集,刷新树

    true:表示获得一个已经存在的jstree实例 $('#tree').jstree(true).destroy();// 清除树节点 // 重新设置树的JSON数据集 $('#tree').jstr ...

  3. XLNet and Robertra

    XLNET         But the AE language model also has its disadvantages. It uses the [MASK] in the pretra ...

  4. [转帖]使用 Vagrant 打造跨平台开发环境

    使用 Vagrant 打造跨平台开发环境 https://segmentfault.com/a/1190000000264347 Vagrant 是一款用来构建虚拟开发环境的工具,非常适合 php/p ...

  5. RDA的使用和说明

    一.RDA 说明 RDA(RemoteDiagnostic Agent)是oracle用来收集.分析数据库的工具,运行该工具不会改变系统的任何参数,RDA收集的相关数据非常全面,可以简化我们日常监控. ...

  6. Codeforces Round #249 (Div. 2) C. Cardiogram

    C. Cardiogram time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  7. LuoguP2698 【[USACO12MAR]花盆Flowerpot】

    题目描述 首先我们简化一下题意: 要找一段区间[L,R],使区间[L,R]内元素最大值减最小值大于等于D. 做法: 首先很容易想到采用二分,分什么呢? 我们二分区间长度为mid 这个时候,检验就成为了 ...

  8. Delphi RSA签名与验签【支持SHA1WithRSA(RSA1)、SHA256WithRSA(RSA2)和MD5WithRSA签名与验签】

    作者QQ:(648437169) 点击下载➨ RSA签名与验签 [delphi RSA签名与验签]支持3种方式签名与验签(SHA1WithRSA(RSA1).SHA256WithRSA(RSA2)和M ...

  9. Redis缓存雪崩、击穿、穿透

    参考大佬 前言 Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行360°的刁难.作为一个在互联网公司面一次拿一次offer的面霸(请允 ...

  10. redis三种集群策略

    主从复制 主数据库可以进行读写操作,当读写操作导致数据变化时会自动将数据同步给从数据库 从数据库一般都是只读的,并且接收主数据库同步过来的数据 一个master可以拥有多个slave,但是一个slav ...