在本文中,我们将尝试理解 Java 内存模型以及垃圾收集是如何工作的。在本文中,我使用了 JDK8 Oracle Hot Spot 64位 JVM。首先,让我描述一下 Java 进程可用的不同内存区域。
启动 JVM 后,操作系统将为进程分配内存。在这里,JVM 本身是一个进程,分配给该进程的内存包括 Heap、 Meta Space、 JIT 代码缓存、线程堆栈和共享库。我们称之为本机内存。“本机内存”是操作系统提供给进程的内存。操作系统分配给 Java 进程的内存量取决于操作系统、处理器和 JRE。接下来让我解释一下 JVM 可用的不同内存块:
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。
最初,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不会扩大。
在上图中,用红色标记的对象表示它们是不可达的(non-reachable)。所有可达的对象都是 GC roots。垃圾收集器不会删除 GC roots。垃圾回收器删除不可达的对象并清空eden space。
对于第二次minor GC,垃圾收集器将从“eden space”和“To survivor space (S0)”标记不可到达的对象,将GC roots复制到另一个survivor space S1,并且可到达对象的年龄将增加。
在上面的图中,标记为红色的对象符合GC条件,其他对象将从eden space和survivor space复制到另一个survivor space S1,并且对象的年龄将递增。
对于每个minor GC,上面的过程都会重复。当对象达到最大年龄阈值时,将这些对象复制到tenured space中。
有一个名为“MaxTenuringThreshold”的JVM级别选项,用于指定对象年龄阈值,以将对象提升到保留区空间。默认值是15。
因此,minor GC显然会从“Young Generation Space”中回收内存。minor GC是一个“stop the world”的过程。有些时候,应用程序暂停可以忽略不计。minor GC将根据应用的GC收集器使用单线程或多线程执行。
如果minor GC触发多次,最终“Tenured Space”将被填满,需要进行更多的垃圾收集。在此期间,JVM触发一个“major GC”事件。有时我们称之为full GC。但是,作为full GC的一部分,JVM从“Meta Space”回收内存。如果堆中没有对象,则加载的类将从元空间中删除。
现在让我们看看 JVM 触发器major GC 的可能性:
在接下来的文章中,我们将分析垃圾收集日志以了解如何调优JVM以获得更好的性能。到那时,请继续关注!
名字解释:
GC roots:
程序仍然在使用的对象,不可达则是程序不在使用的对象
原文链接:https://dzone.com/articles/understanding-the-java-memory-model-and-the-garbag
分享:
崇尚极简,热爱技术,喜欢唱歌,热衷旅行,爱好电子产品的一介码农。
联系QQ:58742094
联系电话:
工作邮箱:
当你的才华还撑不起你的野心的时候,你就应该静下心来学习,永不止步!
人生之旅历途甚长,所争决不在一年半月,万不可因此着急失望,招精神之萎葸。
Copyright 2015- 芒果酷(mangocool.com) All rights reserved. 湘ICP备14019394号
免责声明:本网站部分文章转载其他媒体,意在为公众提供免费服务。如有信息侵犯了您的权益,可与本网站联系,本网站将尽快予以撤除。