JVM学习笔记-GC日志分析(对象优先在Eden区分配)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: JVM学习笔记-GC日志分析(对象优先在Eden区分配)

前言

在进行GC日志分析前,先了解一下JVM虚拟机运行时数据区的主要划分:

20200401134307494.png

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域 有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而一直存在,有些区域则是 依赖用户线程的启动和结束而建立和销毁。根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存 将会包括以上几个运行时数据区域。


由于GC垃圾收集器主要回收的区域是堆区域,所以这里其他的概念用途我这里就不在讲解。

堆是java虚拟机中比较占内存的一部分,也是GC垃圾收集器垃圾回收的重点部分。一个进程有一个java虚拟机实例,一个进程有多个线程,而java堆可被多个线程共享。在虚拟机启动创建时,这个区域的主要目的就是存放对象实例。在《Java虚拟机规范》中对Java堆的描述是:“所有的对象实例以及数组都应当在堆上分配”。

堆内存区域划分

当前主流的垃圾收集器都采用分代收集算法进行垃圾回收。根据对象的生命周期的不同将内存划分为几块,然后根据各块的特点采用最适当的收集算法。大批对象死去、少量对象存活的,使用复制算法,复制成本低;对象存活率高、没有额外空间进行分配担保的,采用标记-清除算法或者标记-整理算法。

20200401134307494.png

如上图可知,堆空间(heap)主要可分为新生代(Young)和老年代(Old Space)区。新生代又可分为

Eden、From Survivor、To Survivor区。

堆的内存模型大致可分为:

20200401134307494.png

先大概了解了java虚拟机的堆空间内存分布,接下来我们就可以去实操查看GC日志,

了解虚拟机的内存分配与回收策略。

对象优先在Eden分配

在大多数情况下,对象在新生代Eden区域内存,当Eden区域没有足够内存进行分配时,虚拟机讲进行一次Minor GC。

新生代收集(Minor GC/Young GC):指目标只是新生代的垃圾收集。

代码分析

在代码的testAllocation()方法中,尝试分配三个2MB大小和一个4MB大小的对象

package com.jvm.slot;
/**
 * @PackageName: com.jvm.slot
 * @author: youjp
 * @create: 2020-09-26 17:01
 * @description: -XX:+UseSerialGC -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
 *
 * -XX:+UseSerialGC 表示强制使用Serial+SerialOld收集器组合
 * -Xms20m 表示堆空间初始大小为 20 M。
 * -Xmx20m 表示堆空间最大大小为 20 M。
 * -Xmn10m 表示新生代大小为 10M。
 * -XX:SurvivorRatio=8 表示Eden:Survivor=8:1
 *
 * @Version: 1.0
 */
public class TestGC {
    public static void main(String[] args) {
        testAllocation();
    }
    public static void testAllocation(){
        byte a1[],a2[],a3[],a4[];
        a1=new byte[2 * 1024*1024]; //2M
        a2=new byte[2 * 1024*1024];// 2M
        a3=new byte[2 * 1024*1024];//2M
        a4=new byte[4 * 1024*1024]; //4M出现一次Minor GC
    }
}

IDEA虚拟机参数配置:

-XX:+UseSerialGC -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails

20200401134307494.png

在运行时通过-Xms20M、-Xmx20M、-Xmn10M这三个参数限制了Java堆大小为20MB,不可扩展,其中 10MB分配给新生代,剩下的10MB分配给老年代。

-XX:SurvivorRatio=8决定了新生代中Eden区与一 个Survivor区的空间比例是8∶1。

-XX:+UseSerialGC指定使用Serial(年轻代)垃圾收集器。其他垃圾收集器可自我尝试。


配置完成后点击运行,查看控制台。

[GC (Allocation Failure) [DefNew: 6612K->1024K(9216K), 0.0075543 secs] 6612K->3201K(19456K), 0.0090275 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [DefNew: 5275K->0K(9216K), 0.0067555 secs] 7453K->7231K(19456K), 0.0068390 secs] [Times: user=0.00 sys=0.02, real=0.01 secs] 
Heap
 def new generation   total 9216K, used 4178K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  eden space 8192K,  51% used [0x00000000fec00000, 0x00000000ff014930, 0x00000000ff400000)
  from space 1024K,   0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
  to   space 1024K,   0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
 tenured generation   total 10240K, used 7231K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
   the space 10240K,  70% used [0x00000000ff600000, 0x00000000ffd0feb8, 0x00000000ffd10000, 0x0000000100000000)
 Metaspace       used 3523K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 382K, capacity 388K, committed 512K, reserved 1048576K
Process finished with exit code 0

从输出的结果也清晰地看到“eden space 8192K、from space 1024K、to space 1024K”的信息,新生代总可用空间为9216KB(Eden区+1个Survivor区的总容量)


执行testAllocation()中分配allocation4对象的语句时会发生一次Minor GC,这次回收的结果是新生代6612KB变为1024KB,而总内存占用量则几乎没有减少(因为allocation1、2、3三个对象都是存活 的,虚拟机几乎没有找到可回收的对象)。


产生这次垃圾收集的原因是为allocation4分配内存时,发现 Eden已经被占用了6MB,剩余空间已不足以分配allocation4所需的4MB内存,因此发生MinorGC。垃圾收集期间虚拟机又发现已有的三个2MB大小的对象全部无法放入Survivor空间(Survivor空间只有 1MB大小),所以只好通过分配担保机制提前转移到老年代去。


这次收集结束后,4MB的allocation4对象顺利分配在Eden中。因此程序执行完的结果是Eden占用 4MB(被allocation4占用),Survivor空闲,老年代被占用6MB(被allocation1、2、3占用)。通过GC 日志可以证实这一点。

20200401134307494.png

为了便于理解,我画了对象进入堆后内存分配流程图

20200401134307494.png

参考博文:

https://www.cnblogs.com/baizhanshi/p/6140925.html?utm_source=itdadao&utm_medium=referral

https://blog.csdn.net/qq_32534441/article/details/86307997


有兴趣的老爷,可以关注我的公众号【一起收破烂】,回复【006】获取2021最新java面试资料以及简历模型120套哦~


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2月前
|
存储 算法 Java
散列表的数据结构以及对象在JVM堆中的存储过程
本文介绍了散列表的基本概念及其在JVM中的应用,详细讲解了散列表的结构、对象存储过程、Hashtable的扩容机制及与HashMap的区别。通过实例和图解,帮助读者理解散列表的工作原理和优化策略。
43 1
散列表的数据结构以及对象在JVM堆中的存储过程
|
10天前
|
缓存 Java
JVM对象引用
本次课程聚焦JVM对象引用,涵盖强引用、软引用、弱引用和虚引用。强引用是最常见的引用类型,确保对象不会被垃圾回收器回收,适用于需要确保对象存活的场景;软引用在内存不足时会被优先回收,常用于缓存;弱引用的对象随时可能被回收,适合临时对象;虚引用最弱,主要用于接收对象回收通知,进行资源清理。通过合理选择引用类型,可优化内存管理,避免内存泄露。
|
3月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
103 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
2月前
|
存储 监控 Java
JVM进阶调优系列(8)如何手把手,逐行教她看懂GC日志?| IT男的专属浪漫
本文介绍了如何通过JVM参数打印GC日志,并通过示例代码展示了频繁YGC和FGC的场景。文章首先讲解了常见的GC日志参数,如`-XX:+PrintGCDetails`、`-XX:+PrintGCDateStamps`等,然后通过具体的JVM参数和代码示例,模拟了不同内存分配情况下的GC行为。最后,详细解析了GC日志的内容,帮助读者理解GC的执行过程和GC处理机制。
|
3月前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
85 3
|
3月前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
66 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
|
3月前
|
算法 Java
JVM进阶调优系列(3)堆内存的对象什么时候被回收?
堆对象的生命周期是咋样的?什么时候被回收,回收前又如何流转?具体又是被如何回收?今天重点讲对象GC,看完这篇就全都明白了。
|
2月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
408 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
21天前
|
监控 安全 Apache
什么是Apache日志?为什么Apache日志分析很重要?
Apache是全球广泛使用的Web服务器软件,支持超过30%的活跃网站。它通过接收和处理HTTP请求,与后端服务器通信,返回响应并记录日志,确保网页请求的快速准确处理。Apache日志分为访问日志和错误日志,对提升用户体验、保障安全及优化性能至关重要。EventLog Analyzer等工具可有效管理和分析这些日志,增强Web服务的安全性和可靠性。
|
3月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
352 3