可能很多人都知道Java程序上生产后,运维人员都会设定好JVM的堆大小,而且还是把最大最小设置成一样的值。那究竟是为什么呢?一般而言,Java程序如果你不显示设定该值得话,会自动进行初始化设定。
  -Xmx 的默认值为你当前机器最大内存的 1/4
  -Xms 的默认值为你当前机器最大内存的 1/64 
  显然这样配置的意义是希望JVM可以根据当前运行的环境,动态伸缩堆内存大小。之所以生产上设置成固定大小,网上也是说法不一,很多时候都是使用“防止内存抖动”这样的模糊词语给出解释。但是我相信各位读者也很懵,不知道这个词具体表达什么含义。
  所以接下来我打算用这篇文章来着重解释一下这其中的门道。带大家彻底弄懂设置固定大小堆的底层原理和好处。为了能顺利看懂本文,我假设你们已经具备了一定的操作系统基础知识。
最大堆或最小堆,从字面上理解就是JVM在运行Java程序时,为其分配堆内存空间的上限和下限值。我们把最大和最小堆设置成相同值那意思就是分配了固定大小的内存呗。这样不就省去了动态调整内存(申请和释放)以及频繁的用户态和内核态的切换带来的开销吗?。如下图所示。
  看上去就是这么回事,简单明了。然而当我们尝试去做个模拟实验,事实却并非如此。比如,随便写个Java程序,使用如下命令启动之。并设置好固定大小堆为1G。
  java -Xmx1024m -Xms1024m -jar demo.jar
  然后我们通过查看进程的内存占用时,发现程序并没有占用1G的空间,而是很小的占用。这个实验结果和我们预期的完全不一致。究竟是什么原因呢?
  问题其实出在我们对内存模型的理解上有问题。很多人可能都是像上面图中那样理解程序分配内存的。实际上是不对的,且也更复杂。首先我们要理解一个重要概念,那就是“进程的虚拟地址空间”,我们用户程序通过malloc这个系统调用申请内存,实际上就是申请了一个虚拟的内存,并不是真正的物理内存。大家要注意,这个虚拟的内存就是指“进程的虚拟地址空间”,而不是我们通常理解的Windows下的虚拟内存或Linux下的swap(分区交换)。如下图所示。
  用户程序申请的虚拟内存(虚拟地址空间),也就是通过malloc系统调用,本质就是在进程的虚拟地址空间里分配了一块地址范围而已。32位系统理论上最大4G,每个进程都有自己的虚拟地址空间,都能申请到最大4G内存。但是申请了的内存,如果没有实际使用(写入数据),则操作系统不会给这块虚拟空间分配实际的物理内存。其实原因很简单,物理内存一直属于紧缺资源,所以现代操作系统都设计为由内核程序统一管理,用户程序无权直接干涉。不是说你申请多少就真的给你多少,而是你实际使用多少才会给你多少。
  回到上面那个小实验,你发现启动后程序内存占用很小就是这个原因。尽管JVM已经在你启动时向系统申请了1G的固定堆大小空间。但是由于你这个程序只是一个简单的测试,里面并没有实际的代码操作业务。所以你实际上只用到了很小的物理内存空间。但是如果你的程序真有业务逻辑,随着系统的运行,实际占用物理内存就会越来越多,直到达到申请的上限值1G。运行期间,你的程序同时也会释放一些对象(通过GC),并在适当的时机归还一些物理内存给操作系统。所以占用的物理内存大小,也会动态有所调整。这样操作系统就可以给其他程序使用,提高了内存利用效率。这样的设计也没什么不好的。
  如上图所示,操作系统对内存管理是以页为基本单位的,一个页代表了一个固定大小的地址范围。用户程序给某个变量比如byte[]赋值时,此时该变量对应的进程虚拟地址空间所在的页在物理内存上找不到对应的页映射时,就会触发了一个缺页中断异常,操作系统就会重新将虚拟地址的页映射到物理内存中的页,此时才是真正实现了内存分配,会占用实际的物理内存空间。假如Java程序的GC把这个byte[]变量收回了,也就是不需要占用内存空间了,用户进程的堆管理器会适当的归还一些物理内存给操作系统,以便下次可以给其他任何程序使用。需要注意的是用户程序调用的malloc和free两个系统调用,都是针对用户进程的虚拟地址空间而言的,并不是实际操作物理内存。只有操作系统才拥有对实际物理内存的管理权限。操作系统可以使用有效的各种算法,来独立高效的管理物理内存。这里面的细节,我这里不详细说了,有兴趣的可以去看些操作系统的资料深入了解下。
  然而我们实际的Java程序,配置成固定堆大小后,你会发现,内存占用一旦上去了就下不来了。即使当前程序处于比较空闲的状态下。这又是为什么呢?难道Java的GC没有回收内存?
  其实并不是GC没有回收内存,而是我们这里存在理解问题。GC回收内存并不是指物理内存,而是指当前进程的虚拟内存(虚拟地址空间)。一般而言,回收的虚拟内存并不会立即归还给操作系统,从而操作系统也就无法回收它了。至于何时归还物理内存,这取决于一个叫glibc的堆管理器。它根据一定的策略和算法适当的释放真实的物理内存。否则即便Java程序GC了对象,该对象占用的物理内存也不会立即释放出来。由于这里我们是设置了固定大小的堆空间,实际上GC回收的虚拟内存,也不会被释放归还给操作系统。故Java进程内存占用一旦增长,内存占用几乎都不会再下降了,这样也是出于对象再分配的效率考虑的。这样显然可以避免操作系统反复把进程的虚拟地址页复映射物理内存页(缺页中断异常)操作,导致频繁的用户态和内核态切换造成的性能问题。
 

Java生产环境JVM设置成固定堆大小深层原理的更多相关文章

  1. Java生产环境下性能监控与调优详解视频教程 百度云 网盘

    集数合计:9章Java视频教程详情描述:A0193<Java生产环境下性能监控与调优详解视频教程>软件开发只是第一步,上线后的性能监控与调优才是更为重要的一步本课程将为你讲解如何在生产环境 ...

  2. 设置JVM参数,查看堆大小

    1.在eclipse设置JVM参数     打开eclipse-窗口-首选项-Java-已安装的JRE(对在当前开发环境中运行的java程序皆生效,也就是在eclipse中运行的java程序)编辑当前 ...

  3. jvm详情——6、堆大小设置简单说明

    年轻代的设置很关键JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存限制.32位系统下,一般限制在1.5G~2G:64 ...

  4. IT兄弟连 Java语法教程 Java开发环境 JVM、JRE、JDK

    要想开发Java程序,就需要知道什么是JVM.JRE以及JDK.JVM是运行Java程序的核心,JRE是支持Java程序运行的环境,而JDK是Java开发的核心,下面我们分别具体介绍它们以及它们之间的 ...

  5. java生产环境增量发版陷阱【原】

    前言 在生产环境,我们为了降低发版风险,一般都只做增量发布,不做全量发布. 除非项目只有一到两人开发,对时间线和代码脉络结构一清二楚,才可全量发布. 然而增量发布也是有一定隐藏陷阱在里面的,以下就是笔 ...

  6. JAVA虚拟机环境变量设置

    转自: 网络    下载java环境变量设置所需的jdk并安装,下载地址:http://www.oracle.com/technetwork/cn/java/javase/downloads/jdk7 ...

  7. 【Odoo 8开发教程】第二章:Odoo生产环境部署设置

    转载请注明原文地址:https://www.cnblogs.com/cnodoo/p/10792977.html 一:dbfilter 数据库访问规则设置 一个odoo实例可以连接到不同的数据库实例中 ...

  8. java jdk 环境变量设置

    我的电脑点右键,选择“属性”,选择“高级”标签,进入环境变量设置,分别设置如下三个环境变量: 设置JAVA_HOME: 一是为了方便引用,比如,JDK安装在C:\jdk1.6.0目录里,则设置JAVA ...

  9. [Java] Tomcat环境变量设置

    @echo off title Tomcat环境变量设置 color 0a set /p inputTH=D:\Work\024_Tomcat if /i "%inputTH%"= ...

随机推荐

  1. 创建HTML文档

    目录 创建HTML文档 构筑基本的文档结构 DOCTYPE元素 DOCTYPE元素 代码清单1 使用DOCTYPE元素 html元素 html元素 代码清单2 使用html元素 head元素 head ...

  2. postman如何解决下个接口依赖上一个接口数据

    解决思路:将上一个接口返回的数据保存起来,然后提供下个接口使用,postman中通过设置全局变量来保存数据 步骤1:在Tests中添加如下图js代码. var jsondata = JSON.pars ...

  3. Java(11)方法详细介绍

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201577.html 博客主页:https://www.cnblogs.com/testero ...

  4. 好奇!仅 13kB 大小的游戏,源码长啥样?

    这个马赛克风格的表情正好 13Kb,有人竟然能用一个表情大小的空间,制作个游戏出来.我就不信这么点的地儿,能写出个花来?游戏能好玩吗?因为这些游戏点开就能玩,我抱着试一试的心态把玩了一会. 事实证明是 ...

  5. QG-2019-AAAI-Improving Neural Question Generation using Answer Separation

    Improving Neural Question Generation using Answer Separation 本篇是2019年发表在AAAI上的一篇文章.该文章在基础的seq2seq模型的 ...

  6. 如何洗白xi校长?(初稿)

    看看咱们太子殿下,谁还敢黑全世界最好的太子殿下 我们不如来考虑一下如何给校长洗白. 第一当然是买断热搜了.买断热搜可以阻止消息进一步传播.当然这种操作学校再8月18日晚就已经做过了.8月18日该条消息 ...

  7. 小白自制Linux开发板 九. 修改开机Logo

    许久不见啊,今天我们继续来修改我们的系统. 通过前面的几篇文章我们已经能轻松驾驭我们的开发板了,但是现在都是追求个性化的时代,我们在开发板上打上了自己的Logo,那我们是否可以改变开机启动的Logo呢 ...

  8. IDEA插件开发,我是如何把公司的发布系统搬到IDEA里的

    不得不说JetBrains公司直的非常的牛B,每一个程序员都能在JetBrains的官方网站找到一款属于自己的开发工具.这些开发工具在工作中给我们带来了巨大的便利.各种各样的基础插件,第三方插件,真是 ...

  9. 数据流中的中位数 牛客网 剑指Offer

    数据流中的中位数 牛客网 剑指Offer 题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就 ...

  10. Python 模块feedparser安装使用

    RSS(简易信息聚合) 简易信息聚合(也叫聚合内容)是一种RSS基于XML标准,在互联网上被广泛采用的内容包装和投递协议.RSS(Really Simple Syndication)是一种描述和同步网 ...