❤️三万字《图解 -JVM调优系列》带你从实战原理上重新认识堆区【建议收藏】❗❗❗

本文详细介绍了Java堆内存的结构、大小设置、分配过程,以及涉及的JVM调优工具和参数。通过实例解析了Minor GC、Major GC和Full GC,探讨了对象在新生代和老年代的生命周期。文章还讨论了逃逸分析、TLAB(Thread Local Allocation Buffer)以及栈上分配的概念,展示了如何利用逃逸分析进行优化。
摘要由CSDN通过智能技术生成

内功修炼系列

vx公众号:码工是小希
关注选择“星标”,重磅干货每日 送达!
【如果你觉得文章对你有帮助,欢迎关注,点赞,留言哦
礼多人不怪嘛,试着回复下:【路线】,【秘籍】,【实战】,【简历】;

有礼送给你哦🎁 个人主页:是我本人,不来看一下?

在这里插入图片描述

好文重点推荐:

❤️故事篇-深入浅出带你搞懂路由协议[ 建议收藏慢慢看 ]
💚“开锁三部曲”——核心基础篇(万字长文安排的明明白白的)
💙《内功修炼系列》之-递归从入门到入土(收藏版)


一 🎂堆的重要概念

堆 针对一个JVM进程来说肯定是唯一的,换句话说就是一个进程只有一个JVM,但我们知道进程包含多个线程,他们是共享同一堆空间的,所以结论是多个线程可以共用同一个JVM的~。在这里插入图片描述
一个JVM实例只对应其一个堆内存,堆也是Java内存管理的核心区域,如上图。

Java堆区在JVM启动的时候即被创建,其空间大小也就确定了。是JVM管理的最大一块内存空间了。

  • 堆内存的大小是可以调节的。
    《Java虚拟机规范》规定,堆可以处于物理上不连续的内存空间上,但在逻辑(地址)上它应该被视为连续的。

所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区(Thread Local Allocation Buffer,TLAB)。

-Xms10m:最小堆内存
-Xmx10m:最大堆内存

下图就是使用:Java VisualVM查看堆空间的内容,通过 jdk bin提供的插件

在这里插入图片描述
《Java虚拟机规范》中对Java堆的描述是:

所有的对象实例以及数组都应该在运行时分配在堆上。(The heap is the run-time data area from which memory for all class instances and arrays is allocated);

我要说的是:“几乎”所有的对象实例都在堆上分配内存。我们从实际使用角度看的。
在这里插入图片描述

因为还有一些对象是在栈上分配的
其中有部分数组和对象可能永远不会存储在栈上,因为栈帧中保存有引用,这个引用指向对象或者数组在堆中的位置。
在这里插入图片描述

在方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集的时候才会被移除。

也就是触发了GC的时候,才会进行回收

如果堆中对象马上被回收,那么用户线程就会受到影响,因为有stop the word堆,是GC(Garbage Collection,垃圾收集器)执行垃圾回收的重点区域
在这里插入图片描述

二 📅堆内存细分

Java 7及之前堆内存逻辑上分为三部分:新生区+养老区+永久区

  • 新生区 Young/New 又被划分为Eden区和Survivor区
  • 养老区 Old/Tenure
  • 永久区 Perm
    Java 8及之后堆内存逻辑上分为三部分:新生区+养老区+元空间

约定:新生区 -> 新生代 -> 年轻代 、 养老区 -> 老年区 -> 老年代、 永久区 -> 永久代; 变化如下图:
在这里插入图片描述

堆空间内部结构,JDK1.8之前从永久代 替换成 元空间

设置堆内存大小与OOM

我们从上面已经知道了,Java堆区是用于存放Java对象实例,那么堆的大小也就是在JVM启动时就已经设定好了,大家可以通过选项"-Xmx"和"-Xms"来进行设置。

  • “-Xms"用于表示堆区的起始内存,等价于-xx:InitialHeapSize
  • “-Xmx"则用于表示堆区的最大内存,等价于-XX:MaxHeapSize

一旦堆区中的内存大小超过“-xmx"所指定的最大内存时,将会抛出outofMemoryError异常。

通常会将-Xms和-Xmx两个参数配置相同的值,其目的是为了能够在ava垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小,从而提高性能。

默认情况下

  • 初始内存大小:物理电脑内存大小/64

  • 最大内存大小:物理电脑内存大小/4


/**

-Xms 用来设置堆空间(年轻代+老年代)的初始内存大小
-X:是jvm运行参数
ms:memory start
-Xmx:用来设置堆空间(年轻代+老年代)的最大内存大小
@create: 2020-07-06-20:44
*/
public class HeapSpaceInitial {
   
public static void main(String[] args) {
   
// 返回Java虚拟机中的堆内存总量
long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
// 返回Java虚拟机试图使用的最大堆内存
long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;
System.out.println("-Xms:" + initialMemory +M);
System.out.println("-Xmx:" + maxMemory +M);
	}
}

输出结果:


-Xms:245M
-Xmx:3614M

如何查看堆内存的内存分配情况,命令如下,并配图:


jps  ->  staat -gc  进程id


-XX:+PrintGCDetails


在这里插入图片描述

OutOfMemory举例

在这里插入图片描述
在这里插入图片描述

我们简单的写一个OOM例子


/**
 * OOM测试
 */
 
public class OOMTest {
   
    public static void main(String[] args) {
   
        List<Integer> list = new ArrayList<>();
        while(true) {
   
            list.add(999999999);
        }
    }
}

然后设置启动参数


-Xms10m -Xmx:10m

运行后,就出现OOM了,那么我们可以通过 VisualVM这个工具查看具体是什么参数造成的OOM
在这里插入图片描述

年轻代与老年代

存储在JVM中的Java对象可以被划分为两类:

  • 一类是生命周期较短的瞬时对象,这类对象的创建和消亡都非常迅速,生命周期短的,及时回收即可

  • 另外一类对象的生命周期却非常长,在某些极端的情况下还能够与JVM的生命周期保持一致

Java堆区进一步细分的话,可以划分为年轻代(YoungGen)和老年代(oldGen)

其中年轻代又可以划分为Eden空间Survivor0空间Survivor1空间(有时也叫做from区、to区)
在这里插入图片描述
下面这参数 开发中一般不会调:
在这里插入图片描述

  • Eden:From:to -> 8:1:1

  • 新生代:老年代 - > 1 : 2
    配置新生代与老年代在堆结构的占比。

  • 默认-XX:NewRatio=2,表示新生代占1,老年代占2,新生代占整个堆的

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙哥手记

非常感谢你的赞赏,一起加油整起

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值