深入理解java虚拟机(linux与jvm内存关系)
本文转载自美团技术团队发表的同名文章
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内存关系)的更多相关文章
- 《深入理解 Java 虚拟机》学习笔记 -- 内存区域
<深入理解 Java 虚拟机>学习笔记 -- 内存区域 运行时数据区域 主要分为 6 部分: 程序计数器 虚拟机栈 本地方法栈 Java 堆 方法区 如图所示: 1. 程序计数器(线程私有 ...
- 深入理解java虚拟机(6)---内存模型与线程 & Volatile
其实关于线程的使用,之前已经写过博客讲解过这部分的内容: http://www.cnblogs.com/deman/category/621531.html JVM里面关于多线程的部分,主要是多线程是 ...
- 深入理解java虚拟机(1)------内存区域与内存溢出
在C++领域,关于C++的内存存储,结构等等,有一本书:深度探索C++对象模型,讲解的非常透彻. 而Java确把这一工作交给了虚拟机来处理. 我们首先来看看关于内存的问题. 1.问题: 1)java ...
- 深入理解java虚拟机----->垃圾收集器与内存分配策略(下)
1. 前言 内存分配与回收策略 JVM堆的结构分析(新生代.老年代.永久代) 对象优先在Eden分配 大对象直接进入老年代 长期存活的对象将进入老年代 动态对象年龄判定 空间分配担保 2. 垃圾 ...
- Java虚拟机详解----JVM内存结构
http://www.cnblogs.com/smyhvae/p/4748392.htm 主要内容如下: JVM启动流程 JVM基本结构 内存模型 编译和解释运行的概念 一.JVM启动流程: JVM启 ...
- 深入理解java虚拟机(1)走进jvm
1.JDK:java程序设计语言.java虚拟机.javaAPI 二.自动内存管理机制 ----------------------------------------------------- 1. ...
- 【深入理解JAVA虚拟机】第二部分.内存自动管理机制.1.内存区域
1.内存区域 根据<Java虚拟机规范(Java SE 7版)> 的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域,如图所示. 程序计数器 当前线程所执行的字节码的行号指 ...
- 深入理解java虚拟机读书笔记1--java内存区域
Java在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途.创建和销毁的时间,有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,有些则是与线程一一对应,随 ...
- 深入理解Java虚拟机读书笔记8----Java内存模型与线程
八 Java内存模型与线程 1 Java内存模型 ---主要目标:定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节. ---此处的变量和J ...
随机推荐
- Struts2数据封装
首先是简单数据类型的封装 jsp页面 <%@ page contentType="text/html;charset=UTF-8" language="java&q ...
- EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器出现no compatible source was found for this media问题的解决
背景分析 EasyDSS流媒体解决方案总体可划分成三个部分:前端视频源设备(PC.手机.摄像机)流媒体数据获取并即时回传.流媒体服务器端直播和录像与回放.客户端直播播放与录像检索回放.前端推流我们使用 ...
- Embarcadero Delphi 7 Lite 7.0.4.453 中文版
https://www.7down.com/soft/116014.html 软件介绍 Embarcadero Delphi 7精简版 是Windows平台下著名的快速应用程序开发工具(Rapid A ...
- [ARM-Linux开发]Linux open函数
Linux open函数 open 函数用于打开和创建文件.以下是 open 函数的简单描述 #include <fcntl.h> int open(const char *pathnam ...
- 【windows】win10新增用户
1.打开[计算机管理]
- pat 1100
1100 Mars Numbers (20 分) People on Mars count their numbers with base 13: Zero on Earth is called ...
- SQL Server 将数据导出为XML和Json
有时候需要一次性将SQL Server中的数据导出给其他部门的也许进行关联或分析,这种需求对于SSIS来说当然是非常简单,但很多时候仅仅需要一次性导出这些数据而建立一个SSIS包就显得小题大做,而SQ ...
- Delphi阿里云短信【支持短信发送、短信批量发送和查询短信发送记录】
作者QQ:(648437169) 点击下载➨Delphi阿里云短信 阿里云api文档 [Delphi 阿里云短信]是最新的阿里云短信接口,不是阿里大于短信接口,支持SendSm ...
- Typora使用技巧系列:(1)
Typora使用技巧(1) 刚刚开了博客怎么说也要学一下markdown语法什么的吧,使用的是编译器是Typora,之后有空会陆续更新的 切换到源代码模:(ctrl + /)临时切换到源代码模式,再按 ...
- 21、Cursorを使う
例: (詳しい内容が後で追加) declare @tempTB table ( PEファンドコード ) ) --1.データ格納用の変数を声明 ) --2.Cursorを声明.内容を定義 declare ...