java 内存模型 gc_理解java的内存模型和垃圾回收

理解java的内存模型和垃圾回收

2020-11-18 18:56:34   作者:Siva Prasad Rao Janapati   来源:dzone

在本文中,我们将尝试理解 Java 内存模型以及垃圾收集是如何工作的。在本文中,我使用了 JDK8 Oracle Hot Spot 64位 JVM。首先,让我描述一下 Java 进程可用的不同内存区域。

85643ffc9de41166324b0ca1e38247d6.png

启动 JVM 后,操作系统将为进程分配内存。在这里,JVM 本身是一个进程,分配给该进程的内存包括 Heap、 Meta Space、 JIT 代码缓存、线程堆栈和共享库。我们称之为本机内存。“本机内存”是操作系统提供给进程的内存。操作系统分配给 Java 进程的内存量取决于操作系统、处理器和 JRE。接下来让我解释一下 JVM 可用的不同内存块:

Heap Memory: JVM 用它来存储对象. 这个内存又被划分为两个不同的区域,叫做 "Young Generation Space"和"Tenured Space"。

Young Generation: 年轻代或新的空间被分为两个部分称为"Eden Space"和"Survivor Space"。

Eden Space: 当我们创建一个对象,内存将从Eden Space分配。

Survivor Space: 它包含 Young 垃圾收集或 Minor 垃圾收集中幸存下来的对象。我们有两个等分的 Survivor Space,分别是 S0和 S1。

Tenured Space: 在minor GC 或young GC 期间达到最大终身阈值的对象将被移动到"Tenured Space"或"Old Generation Space"。

当我们讨论垃圾收集过程时,我们将了解如何使用上述内存位置。

Meta Space: 这个内存是堆内存和本机内存以外的一部分。根据文档默认情况,元空间没有上限。在 Java 的早期版本中,我们称之为"Perm Gen Space"。此空间用于存储类装入器加载的类定义。这个设计是为了增长过程中避免出现内存错误。但是,如果增长超过可用物理内存,则操作系统将使用虚拟内存。这将对应用程序性能产生不利影响,因为从虚拟内存到物理内存(反之亦然)进行数据交换是一项代价高昂的操作。我们有 JVM 选项来限制 JVM 使用的元空间。在这种情况下,我们可能会出现内存溢出错误。

Code Cache: JVM有一个解释器来解释字节代码并将其转换为依赖于硬件的机器码。作为JVM优化的一部分,引入了Just In Time (JIT)编译器。经常访问的代码块将被JIT编译为本地代码,并存储在代码缓存中。JIT编译的代码不会被解释。

现在让我们讨论垃圾收集过程。JVM使用一个单独的demon线程来进行垃圾收集。如上所述,当应用程序创建对象时,JVM尝试从 Eden Space获取所需的内存。JVM执行的GC分为minor GC和major GC。让我们来了解一下minor GC。

c1277cbe4a2df36dda65ccfc9943cb13.png

最初,survivor space和tenured space是空的。当JVM不能从eden space 获取内存时,它会启动minor GC。在minor GC期间,不可达的对象被标记为要收集。JVM选择一个survivor space作为“To Space”。它可以是S0/S1。假设JVM选择了S0作为“To Space”。JVM将可达对象复制到“to Space”S0,并将这些可达对象的年龄增加1。不适合survivor space的对象将被移动到tenured space。这个过程被称为“过早提升”。为了这个图的目的,我把“To Space”设置得比分配的空间大。记住survivor space不会扩大。

17f605a096d21bc2c094d172259f9f89.png

在上图中,用红色标记的对象表示它们是不可达的(non-reachable)。所有可达的对象都是 GC roots。垃圾收集器不会删除 GC roots。垃圾回收器删除不可达的对象并清空eden space。

对于第二次minor GC,垃圾收集器将从“eden space”和“To survivor space (S0)”标记不可到达的对象,将GC roots复制到另一个survivor spaceS1,并且可到达对象的年龄将增加。

87e4dd994196aae81d638aee0382f10a.png

在上面的图中,标记为红色的对象符合GC条件,其他对象将从eden space和survivor space复制到另一个survivor space S1,并且对象的年龄将递增。

f2f7ba590e013b8ecdb53b63f28350d9.png

对于每个minor GC,上面的过程都会重复。当对象达到最大年龄阈值时,将这些对象复制到tenured space中。

14f2b2fba76c9a033a0643aeb2aa313c.png

有一个名为“MaxTenuringThreshold”的JVM级别选项,用于指定对象年龄阈值,以将对象提升到保留区空间。默认值是15。

因此,minor GC显然会从“Young Generation Space”中回收内存。minorGC是一个“stop the world”的过程。有些时候,应用程序暂停可以忽略不计。minorGC将根据应用的GC收集器使用单线程或多线程执行。

如果minorGC触发多次,最终“Tenured Space”将被填满,需要进行更多的垃圾收集。在此期间,JVM触发一个“major GC”事件。有时我们称之为full GC。但是,作为fullGC的一部分,JVM从“Meta Space”回收内存。如果堆中没有对象,则加载的类将从元空间中删除。

现在让我们看看 JVM 触发器major GC 的可能性:

如果开发人员调用System.gc()或Runtime.getRunTime().gc(),则建议JVM启动GC。

如果JVM认为没有足够的tenured space。

在minorGC期间,如果JVM不能从eden或survivor spaces回收足够的内存,那么可能会触发majorGC。

如果我们为JVM设置了“MaxMetaspaceSize”选项,并且没有足够的空间装入新类,那么JVM将触发一次majorGC。

在接下来的文章中,我们将分析垃圾收集日志以了解如何调优JVM以获得更好的性能。到那时,请继续关注!

名字解释:

GC roots:

当前正在执行的方法里的局部变量和输入参数

活动线程(Active threads)

内存中所有类的静态字段(static field)

JNI引用

可达对象:

程序仍然在使用的对象,不可达则是程序不在使用的对象

分享:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值