【JVM】(4)JVM对象创建与内存分配机制深度剖析



指针碰撞,就是一边是用过的,一边是空闲的,中间有个指针,然后挪动指针去分配内存

空闲列表是内存是乱七八糟的,那就要记录那些内存卡是可用的

cas就是比较交换

tlab就是搞个 threadlocal 每个线程去拿他自己持有的内存块

也就是说 在我们的那个堆里面,给我们某具体的线程,分配一块自己独立的空间,我这个线程内部的所有对象都往上面放,这一块空间不可能特别大吧,注意,是有一个参数可以设置它,叫TLAB_SIZE去设置,它默认你不设置的话,好像是伊甸园区的1%吧

如果放不下就走cas放到eden区



我比方说我去,我去,我们上节课给大家去讲过嘛,讲过一个,比方说我,我通过这一个对象,干嘛要去找到这 compute 方法,在元数据区里面那些个代码,怎么去找?

实际上就是通过什么东西啊?

通过这个东西,通过这一个类型指针去找的。

这个代码指的是图片这里的

就是我们整个类的这些个乱七八糟的这些代码

它是放在我们方法区的

我们类装载完之后,JVM内部给我们Java开发人员,我们如果想要访问这个类的一些信息,我们可以通过这一个类,通过这一个类对象,去访问。

在堆区的class是给我们java人员用的

方法区的class存储介质是c++的对象

堆区class不存代码,是存个入口,可以理解为镜像

代码信息在方法区


可以看到Object header就是对象头

还有alignment是用来对齐的


指针压缩




每个线程都有自己的栈空间

test2的作用域 是没有逃逸出这个方法

有个参数可以开启逃逸分析 jdk7后的版本都是默认开启的

如果关闭 对象直接分配在堆上

-XX代表不稳定的参数

栈帧比较小 有可能分配不下这个对象 剩余的空间总大小可以放下 但是没有一整块能放下这个对象

通过标量替换 他可以把一些成员属性 放到零散的内存中 也有参数可以开启 jdk7默认是开启的

运行这个方法一亿次,会分配一亿个对象。

这些对象若分配在堆上,会产生大量 GC。因为方法结束后,这些对象会失去 GC Root 的引用,下一次 GC 时会被回收。

这些对象若分配在栈上,几乎不会发生 GC------ 仅排除其他特殊情况导致 GC 的可能,整体无明显 GC 行为。

对象通常会分配到堆上,且多数情况下会先放入伊甸园区。

此前提到过一个概念:若对象体积较大,或栈内分配失败时,会触发不同的分配规则。

关于大对象的定义后续会具体讲解,大对象会直接被分配到老年代(Old区);若对象体积未达到大对象标准,则会先尝试TLAB分配。

正如之前所说,线程会在伊甸园区为当前线程划分一小块专属内存空间(即TLAB),对象会优先分配到该线程对应的TLAB中------TLAB本质上仍是伊甸园区内的内存空间。

若TLAB分配成功,对象分配流程完成;若TLAB分配失败,则直接在伊甸园区通过CAS机制分配对象。

接下来具体讲解对象分配的相关规则。

总结

  1. 对象默认分配至堆的伊甸园区,大对象会直接进入老年代;
  2. 非大对象优先尝试线程专属的TLAB分配(TLAB位于伊甸园区);
  3. TLAB分配失败时,会通过CAS机制直接在伊甸园区分配对象。

栈帧默认是1M,eden也有五六十兆被占用 这是jvm占用的

eden已经满了 再放一个到eden区,就会触发minor gc

会把存活的对象挪到survivor区


大对象内存分配优化:

提前进入老年代:若系统中有大量大对象且不会被垃圾回收,可设置大对象提早进入老年代,释放年轻代空间,提升性能。

避免内存占用:若大对象不提早进入老年代,会在内存中频繁复制移动,占用内存空间,影响其他对象分配。

eden放不下 有参数可以控制大对象的大小

直接进老年代

"16MB" 实际是 G1 GC 的 Heap Region(堆区域)单元大小 ------G1 会将堆划分为多个等大的 Region,当堆总大小处于 8GB~16GB 区间时,Region 默认大小为 16MB,Eden 区由多个这样的 16MB Region 组成

这种情况为什么要设置一个大对象提早进入老年段,如果你知道你系统里面大量的对象都比较大,

,而且这些对象又是不会被垃圾收集的,那我就可以设置这样大对象,让它提早进入老年段,对不对?

长期存活对象分代年龄设置: 默认分代年龄:一般情况下,对象分代年龄达到 15 岁会挪到老年代,可通过 "Max Tenuring

Threshold" 参数指定。 优化设置依据:若能估算对象生命周期不长,多次 GC 后会被回收,可将分代年龄设置小一些,如设置为 8 或5,节约年轻代空间。




对象动态年龄判断机制: 机制定义:做完 minor GC 后,若一批对象放到年轻代(包括 Survivor 区),其大小超过

Survivor 区的 50%,会将等于及大于该年龄的对象挪到老年代。 案例影响:在电商网站案例中,每 14 秒产生的 60 兆对象因超过

Survivor 区 50%,会挪到老年代,导致老年代很快放满触发 Full GC。

JVM 参数设置方法: 避免随意设置:系统上线前进行发布测试,应根据系统要承载的压力推算 JVM 参数设置,而非随意设置。

依据业务估算:以电商网站为例,可根据订单量、对象大小、业务复杂度等估算每秒往堆中分配的对象大小,进而设置堆、元空间、栈等的大小。

比例设置说明:年轻代中伊甸园区和 Survivor 区默认比例为 8:1:1,但需开启特定参数,且实际比例可能有误差,是否开启要根据业务情况决定。

这里的例子 eden满了,会直接进入old,因为60M超过了S区的50%

old 五六分钟就放满了 触发full gc

不能这么频繁full gc 要做优化 几乎不发生full gc

频繁触发负 GC 问题:当前系统中每五六分钟区域放满触发负

GC,而正常情况应是半小时、几小时甚至几天几周做一次,大促时虽会频繁些,但因垃圾对象导致频繁负 GC 不合适,可对 JVM

参数模型进行优化。 根本原因:对象动态年龄判断机制导致频繁负 GC。

都是朝生夕死的对象 把年轻代放大一点

那就25秒那个对象会被放到s1区,然后其他对象都会被回收

在上线前 要估算一个模型 然后放到测试环境测试一下 然后再去调整参数

老年代分配担保机制讲解: 机制流程:在年轻代做 minor GC 之前,JVM会判断老年代剩余可用空间。若年轻代剩余所有对象大于老年代剩余可用空间,若担保参数未配置则直接做 full GC;若配置了担保参数,会基于历次minor GC 挪到老年代对象的经验值判断,若老年代能放下,就不做 full GC,直接做 minor GC。

担保含义:担保年轻代对象挪到老年代后有可能不触发 full GC。 机制优势:使用该机制,在做 minor GC 之前判断若大概率会做

full GC,先做一次 full GC 再做 minor GC,可使这次 minor GC 时间短,且 full GC能有效回收很多对象,提高效率。






都是负数的 是被回收

没有被回收不会触发这个方法,回收的才会触发这个方法;回收前会触发该方法


这样增加引用 就能避免回收了~

但!!

这个没啥用 看看就好

full gc也会回收方法区的,比如类元信息,那要回收它,必须堆里面的对象都要没有了,那指针就没指向了,自然可以回收掉方法区的东西

相关推荐
亲爱的非洲野猪17 小时前
从ReentrantLock到AQS:深入解析Java并发锁的实现哲学
java·开发语言
星火开发设计17 小时前
C++ set 全面解析与实战指南
开发语言·c++·学习·青少年编程·编程·set·知识
wheelmouse778817 小时前
如何设置VSCode打开文件Tab页签换行
java·python
0思必得017 小时前
[Web自动化] Selenium基础介绍
前端·python·selenium·自动化·web自动化
沛沛老爹17 小时前
Web开发者进阶AI:Agent Skills-深度迭代处理架构——从递归函数到智能决策引擎
java·开发语言·人工智能·科技·架构·企业开发·发展趋势
Good_Starry17 小时前
Java——正则表达式
java·开发语言·正则表达式
二哈喇子!17 小时前
前端HTML、CSS、JS、VUE 汇总
开发语言·前端
欧洵.17 小时前
Java.基于UDP协议的核心内容
java·开发语言·udp
2501_9311624317 小时前
大疆相机:空中影像新境界
python