JVM对象在堆内存中是否如何分配?

这篇具有很好参考价值的文章主要介绍了JVM对象在堆内存中是否如何分配?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1:指针碰撞:内存规整的情况下

2:空闲列表: 内存不规整的情况下

选择那种分配方式 是有 java堆是否规整而决定的。而java堆是否规整是否对应的垃圾回收器是否带有空间压缩整理的能力决定的。

因此当使用Serial,ParNew等带有压缩整理过程的收集器时,系统采用的分配算法是指针碰撞。既简单有高效。

当使用CMS这种基于清楚算法的收集器时,理论是就只能采用复杂的空闲列表。

线程分配缓冲区如果从内存分配的角度来看,所有线程共享的java堆可以划分出多个线程私有的分配缓冲区(ThreadLocal Allocation Buffer, TLAB),以提升对象分配时的效率

JVM对象在堆内存中是否如何分配?,jvm

3:本地线程分配缓冲:对象创建在虚拟机频繁发生,即使仅仅修改一个指指向的位置,在并发的情况下也是线程不安全的,可能正在给A对象分配内存,指针还没有来得及及时修改,对象B又同时使用了原来的指针分配内存的情况。

(1):同步锁定,JVM是采用CAS失败重试来保证操作的原子性

(2):线程隔离,把内存分配的动作按照线程划分在不同的空间中进行,即每个线程在java堆中预先分配一款小内存,成为本地线程分配缓冲。只有本地线程分配缓冲用完了以后,用新的缓冲区区时才需要同步锁定。

JVM如何判断对象可以被回收:

JVM存放着所有的对象,垃圾回收器在堆回收之前,会判断那些对象“”活着“”

引用计数法:

就是为每一个对象添加一个引用计数器,用来统计指向当前对象的引用次数,如果当前对象存在引用的更新,那么就对这个引用计数器进行增加,一旦这个引用计数器变为0,就意味着它可以被回收了。

这种方法需要额外的内存空间来存储引用计数器,但它的原理很简单,判断效率也很高。不过主流的JVM都没有采用这种方式,因为引用计数器在处理一些复杂的循环引用或者相互依赖时,可能会出现一些不再使用但是又无法回收的内存,造成内存泄露的问题。

可达性分析法:

java通过可达性算法分析判断对象是否存活,从这些节点开始,根据引用关系向下搜索,搜索过程走过的路径成为“引用链”。如果某个对象到GC Roots之间没有任何引用链相连(也成为不可达)。就证明此对象是不可能被使用的对象。就会被回收.

JVM对象在堆内存中是否如何分配?,jvm

那些对象可以作为GC Roots?

1、虚拟机栈中的(针栈中的本地变量表)中引用的对象,列如各个线程中被调用方法堆栈中的局部变量,临时变量等

2、元空间的静态属性引用的对象,常量引用的对象。

JAVA的不同引用方式:(是通过可达性算法来说的,来判断这个GCRoot有没有引用或者指向 这个对象,而这里的引用主要分为下面4个类型)

强引用:是指代码之中普遍存在的引用赋值,即类似“Object object = new Object();”。无论任何情况下,只要强引用关系还存在,垃圾收集器就不会回收掉被引用掉的对象。

弱引用:SoftRerfence()内存充足时不回收,不充足时不回收

软引用:WeakRerfence()不管内存是否充足,只要GC一运行就会回收改信用对象

虚引用:很少用,形同虚设,他的作用就是该信用对象被GC回收时触发一个系统通知

JVM对象在堆内存中是否如何分配?,jvm

 JVM里面垃圾回收针对的是 新生代,老年代。还有元空间。

不会针对方法的针栈进行回收,发放一旦执行了。针栈出栈,里面的局部变量就支持从内存中清理清理掉。

代码里创建的对象一般有两种:

一种短期存活的。迅速使用完就会被回收。

一种长期存活的。需要一直生存在java堆内存中。让后续程序不停的使用。

第一种短期存活的对象,通过新生代的S0和S1被垃圾回收15次后,进入老年代中。

为什么要设置老年代和新生代?(就是分代收集理论)

他是建立在两个分代假说之上。

弱分代假说:绝大多数对象都是朝生夕死的

强分代假说:熬过越多次垃圾收集过程的对象越难以消亡。

新生代和老年代有不同的特点,需要不同的垃圾回收算法。

新生的特点时,创建后很快就会被回收,所以需要一种垃圾回收算法。

老年代的特点时,创建后需要很长时间存活,所以需要另外一种垃圾回收算法。

所以需要两个区域来区分垃圾回收算法。

新生代:如果一个区域的对象都是朝生夕死的。那么就就需要把这些对象集中在一起。每次关注时如何保留少量的存活对象,而不是去标记那些大量将要被回收的对象。就能过以较低的代价回收到较大的空间。

老年代:把长期存活的对象集中在在一起。那么虚拟机就可以较低的频率来回收这个区域。这就同时兼顾了虚拟机 垃圾收集器的时间开销和内存开销。

老年代:

为什么要设置 survior1 和 survior2?

首先为什么要设置eden区。如果没有survivor区的话。Eden区每发生一次minor GC时。就会剩余存活的对象将 送入 老年代。当老年代满了以后就会major GC.从而消耗大量时间。所以此时就需要一个缓冲的地方。当Eden发生minjor GC后,将对应存活的对象送入对应的survior。而在survivor1和survivor2中拉回进行转换,只有到15次后,才会移动到对应的老年代,减少对应的major GC.

 第二个问题:为什么设置两个Survival区?因为第一次MinorGC后,Survival就会存在一些存活对象,第二次MinorGC后,Eden区的存活对象会放入Survival区,就会与Survival区之前的对象内存不连续,形成内存碎片,时间一长就会影响性能,因此需要两个Survival区,第一次MinorGC时,Eden区的存活对象转移到fromSurvival区,Eden清空,第二次MinorGC时,将Eden和fromSurvival区中存活对象转移到toSurvival,Eden和fromSurvival清空。fromSurvival和toSurvival交换角色,循环往复15次后,再传向老年代。

Eden区与survivor的比列为什么是 8:1:1

一个eden区是新生代对象出生的地方。

两个survivor区。一个用来保存上次新生代minjor GC后存活下来的对象。两外一个空着。再一次新生代发生minjor后,会将 Eden+survivor中存活的对象都复制到另外一个 survivor中。

据统计证明,90%的对象朝生夕死存活时间极短。每次gc都会回收百分只90的对象。剩下百分之10的空间预留给另外一个survivor区。

讲解常见的垃圾回收算法:

JVM对象在堆内存中是否如何分配?,jvm

 标记-清除算法

JVM对象在堆内存中是否如何分配?,jvm

 分为标记和清楚两个动作。首先统一标记需要回收的对象后,标记完后,然后回收掉被标记的对象。或者也可以返过来,标记存过的对象,回收未被标记的对象。标记的过程就是 属于 垃圾判定的过程。

优点:基于可达性性算法实现,实现简单,后续的收集算法都是通过这种算法实现的

缺陷:

1:执行效率不稳定,如果java堆中有大量的对象,而大部分的对象都是需要回收的。那么此时就需要大量的标记-清除的动作。标记-清除的效率会随着对象的数据递增而降低。

2:标记清除后产生大量的内存碎片,导致程序下一次运行时需要分配一个大的对象而没有足够的连续的内存空间而提前触发一次垃圾回收。

 标记-复制算法

JVM对象在堆内存中是否如何分配?,jvm

核心思想就是“半区复制”。他是将可用内存一分为二,首先使用其中的一块内存,当时使用的一块内存用完后,将使用完内存中的存活对象复制到另外一块内存中。然后再将使用过的内存清空

 优点:实现简单,效率高。解决了标记清楚产生的内存碎片问题。

 缺点: 1:代价太多,将内存空间一份为二,浪费空间。

          2:若存活的对象太多,就会产生大量的复制操作,对应的效率降低。

 标记-整理算法

JVM对象在堆内存中是否如何分配?,jvm

首先这里的标记过程与''标记-清除"的标记过程是一样的。但是后续动作不是直接对可回收对象进行整理,而是对存过的对象都集体移动至内存的一段。

优点:

1:没有划分区域,提高空间利用率

2:没有内存碎片

缺点:

整理的过程中,需要STW,效率变低

 分代算法

现在一般虚拟机的垃圾收集器都采用“分代”算法。

根据对象存活周期不同。将对象内存划分为“新生代”和“老年代”。java根据各个年代的不同特点采用不同的垃圾回收算法。

新生代中每次进行垃圾回收都会发现大量的对象死去。只有少量的对象存活。因此采用复制算法。只要付出少量存过对象的复制成本就可以完成收集。

老年代因为存过率极高,采用标记-清理,标记-整理 算法来进行回收

垃圾收集器:

JVM对象在堆内存中是否如何分配?,jvm

  Serial 垃圾收集器:

JVM对象在堆内存中是否如何分配?,jvm

 单线程工作的垃圾收集器。他先工作是必须要暂停其他所有工作的线程。知道他收集结束。就是所谓的STW.

ParNew垃圾收集器:

JVM对象在堆内存中是否如何分配?,jvm

 他是新生代收集器。是serial收集器的多线程版本。大部分都以一样。在单CPU下,ParNew还需要切换线程,性能可能还不如 Serial

Parallel垃圾收集器

他是新生代垃圾收集器,基于复制,多线程并行的收集器(与ParNew类似)。侧重于达到一个可控的吞吐量。虚拟机允许100分钟。收集一分钟。吞吐量为99%。 吞吐量 = 运行用户代码时间/(运行用户代码时间+运行垃圾收集时间)。主要优点就是自适应调节策略。

-XX:+UseAdaptiveSizePolicy 这个参数是默认开启的。就不需要人工手动调节新生代的大小。Eden和Survivor的比列,晋升老年代大小等细节参数。虚拟机会根据当前系统运行情况收集性能监控指标信息,动态调整这些参数提供最合适的停顿时间来获取最大吞吐量,

JVM对象在堆内存中是否如何分配?,jvm

JVM对象在堆内存中是否如何分配?,jvm

CMS算法

CMS全程Concurrent Mark Sweep, 是老年代垃圾收集器。它是追求最短回收停顿时间为目标的收集器。互联网B/S结构的服务器端特别适合此收集器。

我们知道垃圾回收会带来Stop the World(stw) 的问题,会导致系统卡死时间过长,很多响应无法处理,所以CMS垃圾回收器采取的是垃圾回收线程系统工作线程尽量同时执行的模式来处理的。基于 标记-清除 算法

JVM对象在堆内存中是否如何分配?,jvm

 从上面的过程可以看出的是,垃圾回收器需要经过的是 初始标记、并发标记、重新标记、

初始化标记的过程:(STW,标记一下 GC Roots能直接关联到对象,那么这些对象也就是需要存活的对象,速度很快的)。

并发标记的过程:  (不会STW,追踪GC Roots的整个链路,从 GC Roots的直接关联对象开始遍历整合对象得到引用链路,这个过程耗时比较长但是不需要停顿用户线程,可以与收集线程一起编发运行)

重新标记(STW,修正并发标记期间,因为用户程序继续运行而导致标记产生变化 的哪一部门对象的标记记录,这个阶段的停顿时间通常比较会比初始化标记阶段稍长一些,但也永远比并发标记的时间段,就是对第二段的被系统程序运行变动过的少数对象进行标记,所以允许速度是很快得到)

并发清除不会STW,清理删除掉标记阶段判断已经死亡的对象,由于基于清除算法,不需要移动存活对象,这个阶段可以和用户线程并发执行。)

线上Java项目CPU飘到100%怎么排查?

JVM对象在堆内存中是否如何分配?,jvm

 (首先jstack工具就是:Java堆栈工具,用于生成当前虚拟机当前时刻的线程快照)

top

JVM对象在堆内存中是否如何分配?,jvm

top - H 2266 (拿到这个进程下面的很多线程)

JVM对象在堆内存中是否如何分配?,jvm

printf  '%X' 2287 

 JVM对象在堆内存中是否如何分配?,jvm

jstack 2266 > 2266.txt

 JVM对象在堆内存中是否如何分配?,jvm

sz  2266.txt

 JVM对象在堆内存中是否如何分配?,jvm

 JVM对象在堆内存中是否如何分配?,jvmJVM对象在堆内存中是否如何分配?,jvm

现场Java 服务器内存飘升怎么回事 ?

JVM对象在堆内存中是否如何分配?,jvm

 jamp:java 内存印象工具

jamp命令用于生成堆转储文件。

JVM对象在堆内存中是否如何分配?,jvm

 -heap : 显示java堆中的详细信息,如何使用那种回收器,参数配置,分代情况

-histo : 显示堆中对象统计信息,包括类,实列数量,合计容量

JVM对象在堆内存中是否如何分配?,jvm

调优命令有哪些? Sun JDK监控和故障处理命令有jps jstat jmap jhat jstack jinfo

jps,JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。

jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟 机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。

jmap,JVM Memory Map命令用于生成heap dump文件

jhat,JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内 置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看

jstack,用于生成java虚拟机当前时刻的线程快照。

jinfo,JVM Configuration info 这个命令作用是实时查看和调整虚拟机运行参数。

JVM对象在堆内存中是否如何分配?,jvm

 文章来源地址https://www.toymoban.com/news/detail-600715.html

到了这里,关于JVM对象在堆内存中是否如何分配?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JVM面试题-JVM对象的创建过程、内存分配、内存布局、访问定位等问题详解

    内存分配的两种方式 指针碰撞 适用场合:堆内存 规整 (即没有内存碎片)的情况下。 原理:用过的内存全部整合到一边,没有用过的内存放在另一边,中间有一个分界指针,只需要向着没用过的内存方向将该指针移动对象内存大小位置即可。 使用该分配方式的GC收集器:

    2024年02月08日
    浏览(52)
  • JVM运行时区域——对象创建内存分配过程

            新创建的对象 , 都存放在伊甸园区域 ,当垃圾回收时,将伊甸园区域的垃圾数据销毁,然后将存活的对象转移到幸存者0区域,之后创建的新的对象还是存放在伊甸园区域,等到再次垃圾回收后,将伊甸园区域和幸存者0区域中存活的对象一起转移到幸存者1区域中

    2024年02月15日
    浏览(47)
  • JVM对象创建与内存分配机制深度剖析

    (1)类加载检查 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程; 所以所类加载是 懒加载 ; new指令对应到语

    2024年02月13日
    浏览(49)
  • JVM 垃圾回收详解之内存分配和回收原则+死亡对象判断方法

    当需要排查各种内存溢出问题、当垃圾收集成为系统达到更高并发的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节。 Java 的自动内存管理主要是针对对象内存的回收和对象内存的分配。同时,Java 自动内存管理最核心的功能是 堆 内存中对象的分配与回收

    2023年04月19日
    浏览(58)
  • JVM 创建对象时分配内存的几种方法、分配方法的选择

            假设Java堆中内存是绝对规整的,所有被使用过的内存都被放在一边,空闲的内存被放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那 个指针向空闲空间方向挪动一段与对象大小相等的距离。         如果Java堆中的内存并不是规

    2024年02月10日
    浏览(44)
  • Java进阶(1)——JVM的内存分配 & 反射Class类的类对象 & 创建对象的几种方式 & 类加载(何时进入内存JVM)& 注解 & 反射+注解的案例

    1.java运行时的内存分配,创建对象时内存分配; 2.类加载的顺序,创建一个唯一的类的类对象; 3.创建对象的方式,new,Class.forName,clone; 4.什么时候加载.class文件进入JVM内存中,看到new,Class.forName; 5.如何加载?双亲委托(委派)机制:安全;AppClassLoader; 6.反射实质:能

    2024年02月14日
    浏览(43)
  • JVM 内存分哪几个区,如和判断一个对象是否存活

    JVM 内存分哪几个区,每个区的作用是什么 ? java 虚拟机主要分为以下一个区 : 方法区: 1. 有时候也成为 永久代 ,在该区内很少发生垃圾回收,但是并不代表不发生  GC ,在这里进行的  GC 主要是对方法区里的常量池和对类型的卸载 2. 方法区主要用来存储已被虚拟机加载的类

    2024年02月05日
    浏览(40)
  • C++面试八股文:如何在堆上和栈上分配一块内存?

    某日二师兄参加XXX科技公司的C++工程师开发岗位6面: 面试官: 如何在堆上申请一块内存? 二师兄:常用的方法有malloc,new等。 面试官:两者有什么区别? 二师兄:malloc是向操作系统申请一块内存,这块内存没有经过初始化,通常需要使用memset手动初始化。而new一般伴随三个

    2024年02月08日
    浏览(46)
  • JVM的故事—— 内存分配策略

    堆内存有新生代和老年代,新生代中有一个Eden区和一个Survivor区(from space或者to space)。当有新的对象分配时,会优先分配在Eden区。当Eden区空间不足分配给新对象时,会进行一次minor GC,回收完没有引用的对象后,先考虑把一些Eden区的对象放到Survivor区,如果放不下,就放到老

    2024年02月10日
    浏览(41)
  • 深入理解JVM——垃圾回收与内存分配机制详细讲解

    所谓垃圾回收,也就是要回收已经“死了”的对象。 那我们如何判断哪些对象“存活”,哪些已经“死去”呢? 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加一;当引用失效时,计数器就减1;任何时刻计数器为0的对象就是不可能再被使用的。 但是

    2024年02月12日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包