《剑指JVM》——第7章——设置堆的大小——堆2——运行时数据区篇14

🌈hello,你好鸭,我是Ethan,西安电子科技大学大三在读,很高兴你能来阅读。

✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!

🔥个人主页:Ethan Yankang
🔥推荐:史上最强八股文||一分钟看完我的几百篇博客

🔥温馨提示:划到文末发现专栏彩蛋   点击这里直接传送

🔥本篇概览:详细讲解了运行时数据区的堆——设置堆的大小与查看堆详细的信息。🌈⭕🔥


【计算机领域一切迷惑的源头都是基本概念的模糊,算法除外】


🔥 《剑指JVM》序言-CSDN博客

🔥 《剑指JVM》全书-CSDN博客


🌈章节引出

前一篇章:《剑指JVM》——第7章——堆的核心概念——堆1——运行时数据区篇13-CSDN博客

🌈章节速览


7.2.1 设置堆内存大小

1.默认的内存参数配置原则


Java堆区用于存储Java对象实例,堆的大小在JVM启动时就已经设定好了,可以通JVM 参数“-Xms”和“-Xmx”来进行设置。所示:
“-Xms”用于表示堆区的起始内存,等价于-XX:InitialHeapSize。
“-Xmx”用于表示堆区的最大内存,等价于-XX:MaxHeapSize。

一旦堆区中的内存大小超过“-Xmx”所指定的最大内存,将会抛出内存溢出异常OutOfMemoryError, OOM)。


通常会将“-Xms”和“-Xmx”两个参数配置相同的值。否则,服务器在运行过程中,堆空间会不断地扩容与回缩,势必形成不必要的系统压力。

所以在线上生产环境中,JVM的Xms 和 Xmx 设置成同样大小,避免在 GC后调整堆大小时带来的额外压力。初始内存大小占据物理内存大小的 1/64,最大内存大小占据物理内存大小的 1/4。
下面我们通过代码演示查看堆区的默认配置大小,如代码清单7-4所示。

/**
 * 1.设置堆空间大小的参数
 * -Xms 用来设置堆空间(新生代+老年代)的初始内存大小
 * -X 是 JVM 的运行参数
 * ms 是 memory start
 * -Xmx 用来设置堆空间(新生代+老年代)的最大内存大小
 *
 * 2.默认堆空间的大小
 * 初始内存大小: 物理电脑内存大小的 1/64
 * 最大内存大小: 物理电脑内存大小的 1/4
 *
 * 3.手动设置: -Xms600m -Xmx600m
 * 开发中建议将初始堆内存和最大的堆内存设置成相同的值
 *
 * 4.查看设置的参数:
 * 方式一: jps/jstat -gc 进程id
 * 方式二: -XX:+PrintGCDetails
 *
 * @author atguigu
 */

public class HeapSpaceInitial {
    public static void main(String[] args) {
        // 返回 JVM 中的堆内存总量
        long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
        // 返回 JVM 试图使用的最大堆内存量
        long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;

        System.out.println("-Xms(JVM 中的堆内存初始化量): " + initialMemory + "M");
        System.out.println("-Xmx(JVM 试图使用的最大堆内存量): " + maxMemory + "M");
        System.out.println("系统内存大小为(利用堆的初始内存大小: 物理电脑内存大小的 1/64): " + initialMemory * 64.0 / 1024 + "G");
        System.out.println("系统内存大小为(利用堆的最大内存大小: 物理电脑内存大小的 1/4): " + maxMemory * 4.0 / 1024 + "G");


        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

接下来在命令行中输入如下信息,即可查看本机内存为大致16G。得出的一致。

systeminfo | findstr "物理内存总量"

 

由图7-8可知,最终计算系统内存大小不到15GB,这是因为内存的制造厂商会有不同的进制计算方式,比如现实是以 1000进制计算 GB,而计算机中是以1024进制计算,这样会出现一定的误差。


2.两种方式查看手动设置的JVM的参数


上面案例讲解了默认的内存参数配置原则,那么通过-Xms 和-Xmx 手动配置了参数之后,程序运行起来后如何查看设置的参数呢?这里设置为

-Xms600M -Xmx600M。

继续以代码清单7-4为例,解开sleep 相关代码的注释,运行代码,然后通过以下两种方式查看设置的参数明细。


(1)JPS+讲解jstat栏目

按 Windows+R键打开命令行,输入“jps”查看进程id,再输入“istat -gc进程 id”命令查看参数配置,如图7-9所示。

通过图7-9我们可以看到isat-gs命令下的结果有很多参数选项,下面我们解释其中参数的含义:

讲解jstat的栏目

 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC 
 CCSU   YGC     YGCT    FGC    FGCT     GCT 

这些是与 Java 虚拟机(JVM)的垃圾回收(GC)和内存管理相关的一些指标和参数:

  • s0c:年轻代中第一个 survivor(幸存区)的容量(单位:kb)。
  • s1c:年轻代中第二个 survivor(幸存区)的容量(单位:kb)。
  • s0u:年轻代中第一个 survivor(幸存区)目前已使用空间(单位:kb)。
  • s1u:年轻代中第二个 survivor(幸存区)目前已使用空间(单位:kb)。
  • ec:年轻代中 eden(伊甸园)的容量(单位:kb)。
  • eu:年轻代中 eden(伊甸园)目前已使用空间(单位:kb)。
  • oc:old 代(老年代)的容量(单位:kb)。
  • ou:old 代目前已使用空间(单位:kb)。
  • mc:元数据区(metaspace)已经 committed 的内存空间。
  • mu:元数据区的使用量。
  • ccsc:压缩 class(compressed class space)committed 的内存空间。
  • ccsu:压缩 class 已使用的内存空间。
  • ygc:从应用程序启动到采样时年轻代中垃圾回收(GC)的次数。
  • ygct:从应用程序启动到采样时年轻代中垃圾回收所用的时间(单位:s)。
  • fgc:从应用程序启动到采样时 old 代(全 GC)垃圾回收的次数。
  • fgct:从应用程序启动到采样时 old 代垃圾回收所用的时间(单位:s)。
  • gct:从应用程序启动到采样时垃圾回收用的总时间(单位:s)。


通过计算可以得到堆内存中的大小,S0C加上S1C、EC、OC的大小,正好就是600MB。


详细讲解CCSC、CCSU

在 64 位平台上,HotSpot 使用了两项压缩优化技术,分别是compressed object pointers(“compressed oops”)和compressed class pointers

compressed class pointers指的是,每个 Java 对象的头部有一个引用指向元空间(metaspace)中的klass结构。当使用了compressed class pointers时,这个引用是 32 位的值。为了找到真正的 64 位地址,需要加上一个基准值(base 值)。

然而,这项技术对klass的分配带来了问题:由于 32 位地址只能访问到 4GB 的空间,所以最大只允许 4GB 的klass地址。这意味着 JVM 需要向元空间分配一个连续的地址空间。但当通过调用系统接口malloc(3)mmap(3)从系统申请内存时,操作系统可能返回任意一个地址值,它并不能保证在 4GB 的范围内。

因此,只能用一个mmap()来申请一个区域单独用来存放klass对象。由于需要提前知道这个区域的大小,而且不能超过 4GB,这种方式是不能扩展的,因为这个地址后面的内存可能是被占用的。

只有klass结构有这个限制,对于其他的类元数据(class metadata)则没有必要,因为只有klass实例是通过 Java 对象头部中的压缩指针访问的,其他的元数据都是通过 64 位的地址进行访问,所以它们可以被放到任意的地址上。

基于此,将元空间分为了两个区域:

  • non-class part:包含其他所有的元数据;
  • class part:存放klass对象,需要一个连续的不超过 4GB 的内存,这个区域被称作compressed class space

compressed class space空间的大小可以通过-XX:CompressedClassSpaceSize指定,其默认值是 1GB。需要注意的是,这里的 1GB 并不是真正使用了操作系统的 1GB 物理内存,而是虚拟地址映射。

另外,有两个相关的开关:

  • -XX:+UseCompressedOops:允许对象指针压缩;
  • -XX:+UseCompressedClassPointers:允许类指针压缩。

它们默认都是开启的,也可以手动关闭。如果不允许类指针压缩,那么将没有compressed class space这个空间,并且-XX:CompressedClassSpaceSize这个参数无效。

同时,-XX:-UseCompressedClassPointers需要搭配-XX:+UseCompressedOops,但反过来则不是必须的。也就是说,可以只压缩对象指针,而不压缩类指针。这可能是因为从直觉上来说,压缩对象指针能获得较大的收益,相对更为重要。

此外,对象指针压缩要求堆小于 32GB,如果堆大于等于 32GB,那么对象指针压缩和类指针压缩都会被关闭。

在使用jstat命令查看 Java 虚拟机的统计信息时,ccsc(Compressed Class Space Committed)表示压缩类空间(compressed class space)已提交的内存空间大小。它反映了当前实际为compressed class space分配的内存量。通过观察ccsc的值,可以了解到compressed class space的使用情况,以便进行内存管理和优化。如果发现ccsc的值接近或达到了设置的上限,可能需要考虑调整相关的内存参数,或者优化类的数量和大小等,以避免出现内存不足的情况。


(2)设置 VM options 为“-XX:+PrintGCDetails”

在IDEA中进行设置 VM options 为“-XX:+PrintGCDetails”,参数配置如图1.
所示。


打印下来的信息如图:



补一嘴,说到上面的CPU啥的,下面是自己的电脑配置:

技术面要广系列——自己电脑的配置-CSDN博客



💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖

热门专栏推荐

🌈🌈计算机科学入门系列                     关注走一波💕💕

🌈🌈CSAPP深入理解计算机原理        关注走一波💕💕

🌈🌈微服务项目之黑马头条                 关注走一波💕💕

🌈🌈redis深度项目之黑马点评            关注走一波💕💕

🌈🌈JAVA面试八股文系列专栏           关注走一波💕💕

🌈🌈JAVA基础试题集精讲                  关注走一波💕💕   

🌈🌈代码随想录精讲200题                  关注走一波💕💕


总栏

🌈🌈JAVA基础要夯牢                         关注走一波💕💕  

🌈🌈​​​​​​JAVA后端技术栈                          关注走一波💕💕  

🌈🌈JAVA面试八股文​​​​​​                          关注走一波💕💕  

🌈🌈JAVA项目(含源码深度剖析)    关注走一波💕💕  

🌈🌈计算机四件套                               关注走一波💕💕  

🌈🌈数据结构与算法                           ​关注走一波💕💕  

🌈🌈必知必会工具集                           关注走一波💕💕

🌈🌈书籍网课笔记汇总                       关注走一波💕💕         



📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤收藏✅ 评论💬,大佬三连必回哦!thanks!!!
📚愿大家都能学有所得,功不唐捐!

  • 33
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值