Java虚拟机(JVM)是Java程序运行的基础,它为Java程序提供了一个与硬件和操作系统无关的运行环境。在JVM中,堆内存是程序运行期间,存储对象实例和数组的主要区域。本文将深入探讨Java堆内存的各个方面,包括对象内存布局、JVM内存溢出、垃圾回收机制,以及堆内存的划分和Young GC与Old GC的区别。
1.Java对象内存布局:
JAVA 对象在内存中主要有以下几部分:
1.对象头(Header):
MarkWord:存储对象的运行时数据,如哈希码、GC分代年龄、锁状态标志等。在64位系统中占8字节。
ClassPoint:对象对应的类信息的内存地址,在64位系统中占8字节。
Length:数组对象特有,表示数组长度,占4字节。
2.实例数据(Instance Data):
存储对象的实际数据,即类的属性信息。包含了对象的所有成员变量,大小由变量类型决定。byte、boolean:1 字节 ,short:2 字节 ,char:2~3 字节, int、float:4 字节 ,long、double、引用数据类型:8字节。
3.对齐填充(Padding):
由于内存对齐的原因,这部分不是必须存在,但用于确保对象的大小是8字节的整数倍。
2.JVM内存溢出和垃圾回收机制
2.1JVM内存溢出
JVM内存溢出是指程序在申请内存时,没有足够的内存空间供其使用,这种情况通常发生在堆内存或栈内存不足时。
堆内存溢出(Heap OutOfMemory):最常见的内存溢出,通常发生在创建大量对象时,导致堆内存耗尽。
栈内存溢出(StackOverflowError):当线程请求的栈深度超过了虚拟机所允许的最大深度时抛出。
方法区溢出(PermGen space):在Java 8之前,方法区(PermGen)用于存储类的元数据,当方法区内存不足时会发生溢出。
2.2垃圾回收机制:
为什么要进行垃圾回收: 如果对象只创建不回收,会造成堆内存溢出(OOM)异常。防止内存泄漏:在手动管理内存的语言中,开发者需要确保分配的内存最终被释放。如果忘记释放内存,就会造成内存泄漏,随着时间的推移,这可能导致程序可用内存耗尽,影响程序性能甚至导致崩溃。垃圾回收机制可以自动检测并回收不再使用的对象,从而避免内存泄漏。
垃圾回收(GC)是JVM自动进行内存管理的一种机制,用于回收不再使用的对象所占用的内存空间。Java的垃圾回收主要依赖于以下几个算法:
标记-清除(Mark-Sweep):标记所有存活的对象,然后清除未标记的对象。
复制(Copying):将内存分为两个区域,每次只使用一个区域,当一个区域内存不足时,将存活的对象复制到另一个区域。
标记-整理(Mark-Compact):先标记存活的对象,然后将它们移动到内存的一端,释放边界以外的内存。
为了实现文章内容的完整度,先简单介绍一下垃圾回收机制,后面的课程还会详细介绍。麻烦大家用大大的鼠标狠狠地点个关注!!!
3.JVM堆内存的划分:
Java堆内存通常被划分为以下几个区域:
新生代(Young Generation):新创建的对象首先被分配到这里,为了减少young区垃圾回收后的空间碎片,新生代又分为Eden区和两个Survivor 区,且始终有一个Suvivor区保持闲置。对象会先存放到Eden区当中,Eden区空间 满了之后会进行young区的垃圾回收,之后将young区所有存活的对象复制到闲置 的Suvivor 区中,并清空Eden区和正在使用的Survivor区。
老年代(Old Generation):经过多次GC后仍然存活的对象会被移动到这里。对象会优先分配到新生代内存中,每次GC后没有回收的对象年龄加1,年龄到 15 还没有被回收,对象会存放到老年代内存中;如果对象较大,超过新生代内存的一 半,对象也会存放到老年代区域。
元空间(Metaspace):在Java 8中引入,用于存储类的元数据,取代了永久代(PermGen)。
4.Young GC与Old GC
Young GC(Minor GC):发生在新生代的垃圾回收,通常比较频繁,因为新生代对象的生命周期较短。Eden区满后会触发 YoungGC。
Old GC(Major GC / Full GC):发生在老年代的垃圾回收,通常较少发生,但每次发生时会伴随较长的停顿时间,因为老年代对象的生命周期较长,且需要清理整个堆内存。OldGC非常浪费性能, 所以我们的JVM调优要尽可能减少OldGC的次数, OldGC往往伴随着YoungGC。 YoungGC+OldGC = FullG。
Survivor 区空间并不大,如果满了怎么办?
(1)一般情况下GC会回收95%的对象,且超过15次GC的对象会存放到old 去,所以Survivor区不容易满。
(2)如果Survivor区满了,会触发担保机制,提前将对象存入Old区。
为什么需要Survivor区?
为了减少垃圾回收带来的空间碎片,空间碎片过多会频繁触发YoungGC。
为什么需要两块Survivor区?
为了减少Survivor区的空间碎片。
总结来说,Java堆内存是Java程序运行时存储对象的主要区域,了解其内存布局、内存溢出的原因、垃圾回收机制以及堆内存的划分,对于优化Java程序的性能至关重要。通过合理配置JVM参数,可以有效地减少内存溢出的风险,提高程序的稳定性和性能。
标签:Java,对象,回收,调优,GC,内存,JVM,第五天 From: https://blog.csdn.net/qq_74011163/article/details/142911514