其他分享
首页 > 其他分享> > 运行时数据区-堆

运行时数据区-堆

作者:互联网

目录

概括

  1. 一个jvm实例只有一个堆内存
  2. 所有 Java 虚拟机线程之间共享堆
  3. 堆的内存不需要是连续的,逻辑上它被视为连续的
  4. 堆是在虚拟机启动时创建的
  5. 堆是为所有类实例和数组分配内存的运行时数据区域。
  6. 数组和对象可能永远不会存储在栈上,因为栈帧中保存引用,这个引用指向对象或者数组在堆中的位置。
  7. 在方法结束后,堆中的对象不会被马上移除,而是在垃圾收集的时候被移除
  8. 堆是GC执行垃圾回收的重点区域

内部结构

jdk8以前堆内存逻辑上分为三部分:新生区+养老区+永久代
jdk8及以后堆内存逻辑上分为三部分:新生区+养老区+元空间

设置堆内存大小

  1. "-Xms": 设置堆区的起始内存
  2. "-Xmx": 设置堆区的最大内存
  3. 通常会将 -xms和一Xmx两个参数配置相同的值,其目的是为了能够在java垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小,从而提高性能
  4. 默认情况下,初始内存大小:物理电脑内存大小/ 64、最大内存大小:物理电脑内存大小/4
  5. 查看设置的参数:-Xlog:gc*

年轻代和老年代

年轻代

The young generation consists of eden and two survivor spaces. Most objects are initially allocated in eden. One survivor space is empty at any time, and serves as the destination of live objects in eden and the other survivor space during garbage collection; after garbage collection, eden and the source survivor space are empty. In the next garbage collection, the purpose of the two survivor spaces are exchanged. The one space recently filled is a source of live objects that are copied into the other survivor space. Objects are copied between survivor spaces in this way until they've been copied a certain number of times or there isn't enough space left there. These objects are copied into the old region. This process is also called aging.
每个初始化的对象都进入 JVM 堆,更准确地说,进入位于年轻代的eden 空间。年轻代第一次垃圾收集时。一些对象没有任何引用指向它,它们会被直接删除并压缩它们之间的剩余可用空间。其余的对象,仍然被引用,移动到一个称为幸存者空间的子部分。它会导致stop the world。它对延迟的影响小于从老年代触发stop the world。当 eden 空间已满且无法创建新对象(分配失败)时,会再次触发收集。
每次 GC 运行时,存活的对象的“年龄”都会增加。如果这个年龄达到一个特定的值,可以将相关对象提升到老年代。eden存活的对象存在于 2 个幸存者空间之一中:from或to只有当一个移动对象被认为“足够老”时,它才会被提升到老年代。

老年代

年轻代的对象在垃圾收集中幸存下来的次数达到一定程度后,就会被提升到老年代。

参数

-XX:NewRatio,默认值为2,新生代占1,老年代占2
在HotSpot中,Eden空间和另外两个Survlval空间的比例为8:1:1,可以通过"-XX:SurvivorRatio"设置比例

对象分配过程

  1. 创建的对象存放到Eden区
  2. 如果Eden区满了,垃圾回收器对Eden区进行垃圾回收(Minor GC),将Eden区没有引用指向的对象销毁,再加载新的对象到Eden区
  3. 将Eden区剩余的对象放到幸存者0区
  4. 如果再次进行垃圾回收,上次放到幸存者0区的对象如果没有被回收,会放到幸存者1区
  5. 再次进行垃圾回收回收,放到幸存者0区...
  6. 如果一个对象的存活次数到了一定的值,会进入养老区
  7. 当养老区内存不足时,会触发 Major GC
  8. 养老区进行了 Major GC后如果依然无法进行对象的保存,就会产生OOM异常

GC

  1. Minor GC:新生代的垃圾收集
  2. Major GC:老年代的垃圾收集,只有 CMS GC 会有单独收集老年代的行为
  3. Mixed GC:收集整个新生代和部分老年代的垃圾收集
  4. Full GC: 收集整个Java堆和方法区的垃圾收集

GC触发条件

  1. Minor GC:年轻代空间(Eden区)不足会触发 Minor GC,Survivor满不会触发GC,Minor G C会引发STW
  2. Major GC:老年代空间不足会先尝试触发 Minor GC,如果还是空间不足会进行 Major GC,Major GC 的速度一般会比Minor GC慢10倍以上,STW时间更长
  3. Full GC:有以下五种情况,应尽量避免 Full GC
    3.1 调用System.gc(),系统会建议执行Full GC,不一定会执行
    3.2 老年代空间不足
    3.3 方法区空间不足
    3.4 通过 Minor GC 后进入老年代的平均大小大于老年代的可用内存
    3.5 由Eden区、survivor spacee (From Space)区向survivor space1 (ToSpace)区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

内存分配策略

  1. 优先分配Eden
  2. 大对象直接分配到老年代
  3. 长期存活的对象分配到老年代
  4. 如果survivor区中相同年龄的所有对象大小的总和大于survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。
  5. 空间分配担保:-xx: HandlePromotionFailure

TLAB

什么是TLAB

Thread Local Allocation Buffer:线程私有的缓冲区,包含在Eden空间内

为什么有TLAB

  1. 在并发环境下从堆区中划分内存空间是线程不安全的
  2. 为避免多个线程操作同一地址,需要使用加锁等机制,进而影响分配速度。

逃逸分析

什么是逃逸分析

逃逸分析是一个分析过程。它检测对象是否在编译单元之外可见(编译单元通常是一个方法加上任何其他内联到其中的方法。)对象可以通过返回或作为参数传递给另一个方法而在编译单元之外变为可见。

标量替换

  1. 标量(scalar)是指一个无法再分解成更小的数据的数据。Java中的原始数据类型就是标量。
  2. 还可以分解的数据叫聚合量(aggregate),例如Java中的对象。
  3. 在JIT阶段,如果经过逃逸分析,发现一个对象不会被外界访问的话,那么经过JIT优化,就会把这个对象拆解成若干个其中包含的若干个成员变量来代替。这个过程就是标量替换。
  4. 参数:-XX:+EliminateAllocations,默认是开启的
  5. 只有在Server模式下,才可以启用逃逸分析

结论

在HotSpot中采用了标量替换

标签:survivor,Eden,对象,GC,垃圾,数据,年代,运行
来源: https://www.cnblogs.com/ftlzypx/p/15662468.html