精华内容
下载资源
问答
  • Java 对象分配过程

    2021-04-20 21:08:57
    对象分配是一个严谨和复杂的任务,JVM的设计者们不仅需要考虑内存如何分配、在哪里分配的问题,并且由于内存分配算法与内存回收算法密切相关,所以还需要考虑GC执行完是否会在内存空间中产生内存碎片。 ...
    • 对象分配是一个严谨和复杂的任务,JVM的设计者们不仅需要考虑内存如何分配、在哪里分配的问题,并且由于内存分配算法与内存回收算法密切相关,所以还需要考虑GC执行完是否会在内存空间中产生内存碎片。

    新生代主要分为:Eden区和两个 Survio区 (下图的 S0 和 S1)

    在这里插入图片描述

    如上图:对象创建以后,先分配到 Eden 区,当Eden区放满了以后,开始垃圾回收(YGC/Minor GC),加入红色的对象不需要了,则进行释放,绿色的还有引用,则分配到 S0区(to区),然后对象的年龄计数器增加1。

    在这里插入图片描述

    Eden区继续存储对象,再次存储满了以后,进行YGC,无用对象被清除,绿色存在引用的对象和上面S0区的对象 统一都放入到 S1(to)区中,引用计数器增加1,然后S0 清空了,就这样反复.

    在这里插入图片描述

    当对象引用计数器的指达到15(默认的阈值位15),把这对象放入老年代。

    s0和s1,复制之后有交换,谁空谁是to。
    垃圾回收频繁在新生区收集,很少在养老区收集,几乎不在永久区/元空间收集。

    注意:当 Eden 区满的时候,会触发 YGC 操作对 Eden和S0,S1进行GC操作,但是 Survio 满了不会触发 YGC。如果新声代放不下,可以考虑直接放到老年代,如果老年代也放不下了进行 FGC/Major GC,如果FGC以后还是放不下 报 OOM…

    在这里插入图片描述

    • Minor GC 、 Major GC 、Full GC 区别

    JVM在进行 GC 时,并非每次都对 (新生代、老年代、永久代/元空间)进行一起回收,大多数还是对新生代GC。
    针对 HotSpot VM的实现,它里面的GC按照回收区域,又分为两大类型:一种是部分收集(Partial GC),一种是整堆收集(Full GC)。
    在这里插入图片描述

    展开全文
  • java性能优化实践jvm调优策略工具83.93元包邮...对象的内存分配,往大方向上讲,就是在堆上分配对象主要分配在新生代的 Eden 区上,如果启动了本地线程分配缓冲,将按线程优先在 TLAB 上分配。少数情况下也可能直...

    java性能优化实践jvm调优策略工具

    83.93元

    包邮

    (需用券)

    去购买 >

    2fdfb0b06970c6be881137d952161266.png

    一、概要

    前面的文章介绍了对象的创建过程,其中第三步 —— 分配内存,只是简单的介绍了分配的方式 —— 指针碰撞、空闲列表,其实对象在堆上分配还大有文章嘞。

    对象的内存分配,往大方向上讲,就是在堆上分配,对象主要分配在新生代的 Eden 区上,如果启动了本地线程分配缓冲,将按线程优先在 TLAB 上分配。少数情况下也可能直接分配在老年代中,分配的规则并不是百分之百固定的。其细节取决于当前使用的是哪一种垃圾收集器的组合,还有虚拟机中与内存相关的参数的设置。

    cb61a561095d9784593152410ee0448c.png

    下面介绍一些常见的内存分配策略。

    二、对象优先在 Eden/TLAB 分配

    虚拟机将新生代内存分为一块较大的 Eden 空间和两块较小的 Survivor 空间(默认比例是 8:1:1),大多数情况下,分配对象时,使用 Eden 和其中一块 Survivor 空间,当没有足够空间进行分配时,虚拟机将会进行一次 MinorGC。

    如果虚拟机打开了 TLAB,那么对象优先在 TLAB 上分配。TLAB 全称是本地线程分配缓冲(Thread Local Allocation Buffer),它是每个线程在 Java 堆中预先分配的一小块内存。因为 TLAB是线程私有的,没有锁开销,因此性能较好,在 JDK7 之后默认开启。

    三、大对象直接进入老年代

    虚拟机提供了一个 -XX:PretenureSizeThreshold 参数,令大于这个设置值的对象直接在老年代分配,这样做的目的是避免在 Eden 区和及两个 Survivor 区之间发生大量的内存复制。注意!该参数只对 Serial 和 ParNew 收集器有效,Parallel Scavenge 并不认识该参数。

    一般我们代码中常见的大对象是指那种很长的字符串以及数组,写程序的时候应当避免,经常出现大对象容易导致内存还有不少空间时就提前触发垃圾收集以获取足够的内存空间来“安置”它们。

    四、长期存活的对象将进入老年代

    还记得前面文章我们介绍对象创建的时候,说到对象头中有一个 “GC 分代年龄” 吗?那么这个是做啥用的呢?

    如果对象在 Eden 出生并经过第一次 Minor GC 后仍然存活,并且能被 Survivor 容纳的话,将被移动到 Survivor 空间中,并且对象年龄设为1。对象在 Survivor 空间中每“熬过”一次 Minor GC,年龄就增加 1 岁,当它的年龄到达一定程度(最大为 15 岁),就将会被晋升到老年代。对象晋升老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 设置。

    对象是否能够晋升到老年代,也不全由 -XX:MaxTenuringThreshold 参数控制,如果 Survivor 空间中相同年龄的所有对象大小总和大于 Survivor 空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。

    五、空间分配担保

    新生代在发生 Minor GC 之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象之和(或者历次晋升老年代对象的平均大小)。如果这个条件不成立,那么虚拟机将直接进行 Full GC 动作;如果这个条件成立,那么虚拟机就会进行一次 Minor GC 操作,但是这次 Minor GC 是有风险的,因为比较的值是平均值,可能出现极端的情况 —— 大量对象在 Minor GC 后还存活,这时就只好在失败后重新发起一次 Full GC。

    原文链接:https://www.cnblogs.com/jmcui/p/12072631.html

    java 11官方入门(第8版)教材

    79.84元

    包邮

    (需用券)

    去购买 >

    f0f3f55624fb396b1764d42d6df88864.png

    展开全文
  • 本文来说下G1垃圾收集器之对象分配过程 文章目录概述 概述 G1的年轻代由eden region 和 survivor region 两部分组成,新建的对象(除了巨型对象)大部分都在eden region中分配内存,如果分配失败,说明eden region...

    本文来说下G1垃圾收集器之对象分配过程


    概述

    G1的年轻代由eden region 和 survivor region 两部分组成,新建的对象(除了巨型对象)大部分都在eden region中分配内存,如果分配失败,说明eden region已经被全部占满,这时会触发一次young gc,回收eden region的垃圾对象,释放空间,满足当前的分配需求。

    在这里插入图片描述


    小对象

    G1默认启用了UseTLAB优化,创建对象(小对象)时,优先从TLAB中分配内存,如果分配失败,说明当前TLAB的剩余空间不满足分配需求,则调用allocate_new_tlab方法重新申请一块TLAB空间,之前都是从eden区分配,G1需要从eden region中分配,不过也有可能TLAB的剩余空间还比较大,JVM不想就这么浪费掉这些内存,就会从eden region中分配内存。

    allocate_new_tlab方法的实现:

    在这里插入图片描述
    这只是TLAB申请入口,真正的实现位于attempt_allocation方法中,优先尝试在当前的region分配。

    attempt_allocation方法的实现:

    在这里插入图片描述
    其中_mutator_alloc_region在实现上继承自G1Allocregion,内部持有一个引用_alloc_region,指向当前正活跃的eden region,可以看成是该region的管理器,其attempt_allocation方法负责在该region中分配内存。

    G1Allocregion::attempt_allocation方法的实现:

    在这里插入图片描述
    每个region内部管理着一块逻辑连续的地址空间,在并发情况下,采用指针碰撞方式进行内存分配,避免了效率低下的加锁操作。

    指针碰撞实现原理:

    在这里插入图片描述
    如果上述分配动作返回NULL,说明当前该region空间不足,导致分配失败,继而调用attempt_allocation_slow方法,执行慢路径进行分配。

    慢路径的实现如下:

    在这里插入图片描述
    慢路径的逻辑主要是申请一个新的region,不过可能存在多个线程同时申请,所以在申请动作发生之前,需要进行加锁操作,由于调用层级比较多,暂时忽略中间步骤,分析最终实现。

    G1CollectedHeap::new_mutator_alloc_region方法实现:

    在这里插入图片描述
    其中force为false,is_young_list_full方法判断当前young_list中的region数是否已经超过阈值_young_list_target_length,实现如下:

    bool is_young_list_full() {
    
        uint young_list_length = _g1->young_list()->length();
        uint young_list_target_length = _young_list_target_length;
        return young_list_length >= young_list_target_length;
      }
    

    其中_young_list_target_length,在gc之后会重新计算得到一个合理的值,如果当前young region的数量还没达到阈值,则可以通过new_region()方法获取一个新的region,否则返回NULL。

    在这里插入图片描述
    如果返回NULL,说明没有申请到一个新的region,接下去还会判断GC_locker的状态,如果GC_locker::is_active_and_needs_gc(),说明很快会有一个gc操作,并且region list还有扩大的可能(region list的大小还没有达到_young_list_max_length),则可以执行_mutator_alloc_region.attempt_allocation_force强制申请一个新的region,但是强制申请也是有可能失败的(整个堆内存耗尽,不过这种情况很少出现)

    如果都失败的话,这个时候确实需要来一发gc治疗一下了

    在这里插入图片描述
    这次gc和后续的大对象分配失败触发的gc过程是一样的。


    大对象

    前面描述的小对象的内存分配过程,如果当前分配的是大对象,由于在TLAB中放不下,这时只能走G1CollectedHeap::mem_allocate()逻辑进行分配:

    在这里插入图片描述

    判断当前分配的大小是否满足巨型对象(超过region大小的一半),如果不是巨型对象,则通过attempt_allocation()的碰撞指针方式进行分配。如果是巨型对象,则执行attempt_allocation_humongous()方法进行分配,在申请内存之前,会进行MutexLockerEx x(Heap_lock)加锁操作,根据所分配的大小计算出至少需要多少个连续的region。

    1. 如果只需要一个region,通过new_region()直接返回一个可用的region即可。
    2. 如果需要多个region,则从空闲可用的region列表中找到多个连续的region,并返回第一个region的序号。
    3. 如果不存在这么多个连续的region,则会扩大堆内存,尝试再次分配。
    4. 如果扩大堆内存还是不够(一般情况是够的,因为是按需要的大小进行扩大,除非可扩大容量已经很小了),有可能会触发一次gc操作。

    在这里插入图片描述

    巨型对象分配失败之后:

    在这里插入图片描述

    根据当前的GC_locker的状态,决定是否执行本次gc

    在这里插入图片描述

    如果需要,则执行do_collection_pause方法触发一次gc动作

    在这里插入图片描述
    这里触发的gc是VM_G1IncCollectionPause,具体的gc过程,在后续文章继续进行分析,等完成之后,再次尝试分配。


    本文小结

    本文详细介绍了G1垃圾收集器之对象分配过程。

    展开全文
  • JAVA 对象分配过程

    2021-03-11 11:48:50
    1. 在JAVA中,对象的...2. 类加载完成后,会为该对象分配内存空间。一个对象需要多大的内存空间在类加载完成后就确定了。分配内存有两种方法,依据内存空间是否规整来确定。如果被内存空间是规整的,只要把空闲指...

    1. 在JAVA中,对象的分配一般使用new关键字。

    当虚拟机遇到new指令时,会先检查该指令所包含的参数在常量池中能否找到一个符号引用,并检查该符号引用所代表的类是否被加载、解析和初始化。

    如果没有,则会先执行类的加载过程。

    2. 类加载完成后,会为该对象分配内存空间。一个对象需要多大的内存空间在类加载完成后就确定了。

    分配内存有两种方法,依据内存空间是否规整来确定。

    如果被内存空间是规整的,只要把空闲指针向空闲内存方向挪动即可,这种方法称为“指针碰撞”;

    如果内存空间不是规整的,需要有一个“空闲列表”用于记录哪些内存是可用的,并从可用内存中分配足够大小的内存出来,并修改“空闲列表”;

    在使用Serial、ParNew等算法时是用的指针碰撞;使用Mark-Sweep等算法时,采用空闲列表。

    3. 在多线程环境下怎么保证分配内存的动作是线程安全的。

    一种方法是对分配内存的动作进行同步;

    另一种方法是使用“本地线程分配缓存(TLAB)”,每个线程会预先分配到一块内存,申请内存会在各自的TLAB上进行;只有当TLAB不够是,才需要同步分配新的TLAB;

    4. 分配好内存后,虚拟机会将除对象头以外的空间初始化为0。这就是为什么JAVA代码中的全局变量可以不用初始化也可以使用的原因。

    此外,虚拟机还会对对象头进行必要的设置,比如对象所属的类,对象的哈希码,对象的GC分代年龄等信息。

    5. 上述过程完成或,虚拟机认为一个对象已经创建完毕,但是从程序来看,对象还没有初始化,因此需要根据代码初始化各个变量。

    这一步完成后,一个可用的对象就创建好了。

    展开全文
  • Java 对象分配流程 我们这里不考虑栈上分配,这些会在 JIT 的章节详细分析,我们这里考虑的是无法栈上分配需要共享的对象。 对于 HotSpot JVM 实现,所有的 GC 算法的实现都是一种对于堆内存的管理,也就是都实现了...
  • 如果对堆中的分代概念不是很明白,请务必看完博客:堆以及堆分代的详细介绍,接下来对堆中对象分配的过程进行详细的说明。 1、背景 为新对象分配内存是一件非常严谨和复杂的任务,JVM的设计者们不仅需要考虑内存如何...
  • Java对象分配流程

    2021-04-17 17:38:36
    在学习Java的过程中,很多喜欢说new出来的对象分配一定在对上; 其实不能这么说,只能说大部分对象分配是在对上。通过对象的分配过 程分析,除了堆以外,还有两个地方可以存放对象: 栈和TLAB(Thread Local ...
  • 内存分配对象栈上分配
  • 当一个对象被创建了,那在JVM中是如何的从一个对象不存在到存到,然后将对象存放在什么地方呢?这次主要来探讨一下Java对象创建的过程。new关键字创建对象的3个步骤:1、在堆内存中创建出对象的实例。当我们用new...
  • 文章目录1、对象的创建1.1、类加载检查1.2、分配内存1.3、初始化1.4、设置对象头1.5、执行方法 1、对象的创建 对象创建的主要流程: 1.1、类加载检查 ... 在类加载检查通过后,接下来虚拟机将为新生对象分配内存
  • 不同于大家所熟知的对象分配在堆空间中,在GC中中会回收堆中不再使用的对象,但标记筛选以及回收整理空间都需要消耗大量资源,所以如果一个对象能分配在栈空间中,不在使用时可以直接从栈中弹出,不在经过 ...
  • 但新生代Eden(伊甸园区)占了160M, Survivor0,Survivor1各占了20M 注意:新生代中的Survivor默认有一个是不会供我们使用的, 两个幸存者区他们使用的是标记-复制算法 4、图解对象分配过程(重点) 4.1、对象分配过程 ...
  • 一、对象的创建1....2.分配内存在类加载完成后就可以完全确定对象所需内存了,这时内存分配可以分为两种,java堆内存规整和不规整。java堆是否完整取决于垃圾收集器是否带有压缩整理功能。1.指针碰撞...
  • 一、对象创建流程分析   1、类加载检查 jvm遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那...
  • JVM调优-大对象分配

    千次阅读 2021-01-01 17:09:12
    每当应用程序使用G1收集算法时,GC时对大对象的分配可能会影响应用程序的性能(强调:大对象分配是指大于region大小的50%对象的分配)。 频繁地大对象分配会引发一下GC性能问题: 如果region当中包含大对象,剩余...
  • 对象分配内存

    2021-12-12 11:58:20
    对象优先在Eden分配 一般情况下,对象在新生代Eden区中分配,当Eden区没有足够的空间进行分配时,虚拟机将发生一次Minor GC. HotSpot虚拟机提供了 -XX:+PrintGCDetails这个收集器日志参数,告诉虚拟机在发生垃圾收集...
  • 对象创建要考虑的两个问题1、内存分配算法指针碰撞算法,将内存区域分成两部分中间采用指针分隔开来,分配对象就将指针向一个方向移动,这种需要内存区域规整。不规整就要通过空闲列表来记录那块内存是否空闲。内存...
  • JVM对象分配详解

    2021-02-07 21:15:57
    1. JVM对象分配流程 2.栈上分配 JVM提供的一项优化技术,它的基本思想是,对于那些线程私有对象(指不可能被其他线程访问的对象)可以将它们打散分配在栈上,而不是分配在堆上。 基本思想: 将线程私有的对象打散...
  • 对象分配过程1.对象分配难点2.图解对象分配过程3.额外补充4.对象分配的特殊情况5.代码演示对象分配过程 1.对象分配难点 为新对象分配内存是一件非常严谨和复杂的任务,JVM的设计者们不仅需要考虑内存如何分配、在...
  •  ② new A()会导致在堆内存中分配一块空间,该内存中的A对象同时会含有a和b。 ③ work()方法会在codesegment区中分配内存。 ④ 如果此时 A b = a;则表示把a的值复制给b,即b的值为a中保存的地址。 一、基本概念
  • 对象创建对象创建分为三部分,首先是类加载,接着是为对象分配内存,最后是初始化。创建虚拟机遇到new指令时会去检查这个指令参数是否能在常量池中定位到一个符号引用,并检查这个符号引用代表的类是否已被加载、...
  • 前言 本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!...从上面就可以看出,Java 对象实际上给 JVM 带来了很多负担,也给服务器带来了麻烦
  • Java对象内存分配流程

    2021-01-29 09:42:32
    针对不同年龄段的对象分配原则 优先分配到Eden区 大对象(过长的字符串、数组)直接分配到老年代,尽量避免程序中出现过多的大对象 长期存活的对象分配到老年代 动态对象年龄判断 如果survivor区中相同年龄的所有...
  • Java中的栈上分配

    2021-03-08 01:51:38
    什么是栈上分配栈上分配是java虚拟机提供的一种优化技术,基本思想是对于那些线程私有的对象(指的是不可能被其他线程访问的对象),可以将它们打散分配在栈上,而不是分配在堆上。分配在栈上的好处是可以在函数调用...
  • Java一门面向对象的语言,在Java中使用的对象都需要被创建出来,在Java中创建一个对象的方法有很多种,但对象在创建过程中都需要进行内存分配。Java对象内存分配过程保证线程安全,对象的内存分配过程就必须进行同步...
  • 文章目录运行时数据区程序计数器native方法栈方法区:直接内存jvm栈java堆hotspot对象(不包括数组和Class对象)对象的内存布局对象的访问定位对象分配流程分配对象的同步问题 运行时数据区 程序计数器 native方法栈...
  • 分配程序员通过new为每个对象申请内存空间(基本类型除外),所有对象都在堆中分配空间;释放:对象的释放是由垃圾回收机制决定和执行的。Java内存分为两种:栈内存和堆内存(1)在函数中定义的基本类型变量(即基本类型...
  • Java所承诺的自动内存管理主要是针对对象内存的回收和对象内存的分配.在 Java虚拟机的五块内存空间中,程序计数器、Java虚拟机栈、本地方法栈内存的分配和回收都具有确定性,一半都在编译阶段就能确定下来需要分配的...
  • golang内存分配与管理

    2021-03-12 15:42:04
    ​ golang的内存分配机制源自Google的tcmalloc算法,英文全称thread caching malloc,从名字可以看出,是在原有基础上,针对多核多线程的内存管理进行优化而提出来的。该算法的核心思想是内存的多级管理,进而降低锁...
  • 原标题:JVM对象的内存分配对象优先在伊甸园分配对象直接进入老年代JVM参数-XX:+PrintGCDetails在发生垃圾收集行为时打印内存回收日志,并且在进程退出的时候输出当前的内存各区域分配情况。Minor GC VS Full GC...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,195,594
精华内容 478,237
关键字:

对象分配