首页 > 系统相关 >4. JVM 运行时内存

4. JVM 运行时内存

时间:2024-12-26 17:33:33浏览次数:4  
标签:Major 对象 回收 GC 内存 JVM 运行

Java 堆从 GC 的角度还可以细分为:

  • 新生代(Eden 区、From Survivor(S0) 区和 To Survivor 区(S1))
  • 老年代

1. 新生代
a)Eden 区
Java 新对象的出生地(如果新创建的对象占用内存很大,则直接分配到老年代)。
当 Eden 区内存不够的时候就会触发 MinorGC,对新生代区进行一次垃圾回收。
b)ServivorFrom
上一次 GC 的幸存者,作为这一次 GC 的被扫描者。
c)ServivorTo
保留了一次 MinorGC 过程中的幸存者。
d)MinorGC 的过程(复制->清空->互换)
MinorGC 采用复制算法
1:eden、servicorFrom 复制到 ServicorTo,年龄+1
首先,把 Eden 和 ServivorFrom 区域中存活的对象复制到 ServicorTo 区域(如果有对象的年龄以及达到了老年的标准,默认年龄达到15,则赋值到老年代区),同时把这些对象的年龄+1(如果 ServicorTo 不够位置了就放到老年区);
2:清空 eden、servicorFrom
然后,清空 Eden 和 ServicorFrom 中的对象;
3:ServicorTo 和 ServicorFrom 互换
最后,ServicorTo 和 ServicorFrom 互换,原 ServicorTo 成为下一次 GC 时的 ServicorFrom区。

2. 老年代
主要存放应用程序中生命周期长的内存对象。
老年代的对象比较稳定,所以 Major GC(也称Full GC) 不会频繁执行。在进行 MajorGC 前一般都先进行了一次 MinorGC,使得有新生代的对象晋身入老年代,导致空间不够用时才触发。当无法找到足够大的连续空间分配给新创建的较大对象时也会提前触发一次 MajorGC 进行垃圾回收腾出空间。

a)Major GC 的触发条件
Major GC 的触发通常发生在以下几种情况:

  • 老年代内存不足:当老年代内存满时,JVM 会触发 Major GC 来释放空间。
  • 晋升失败:如果年轻代的对象因为存活时间过长而无法晋升到老年代,这也可能触发 Major GC。
  • 显式调用 System.gc():虽然不推荐使用,但调用 System.gc() 方法会请求进行 Full GC。
  • 类卸载:在类被卸载时(如应用程序退出或类加载器被回收),也会触发 Major GC。

b)Major GC 的过程
1:标记(Mark):首先,JVM 会标记老年代中存活的对象,找到哪些对象是活动的。
2:清理(Sweep):清理掉不再被引用的对象,释放内存空间。
3:压缩(Compact):对于老年代的碎片化,JVM 可能需要压缩内存,即将存活的对象移动到堆的另一部分,从而释放出更大的连续内存空间。这个步骤会增加垃圾回收的时间。

d)优化 Major GC
因为 Major GC 是最耗时的垃圾回收操作之一,开发者可以通过以下几种方式来减少 Major GC 的发生频率:

  • 增加堆内存大小:增加 JVM 堆的大小,特别是老年代的大小,可以减少老年代频繁发生 Full GC 的概率。
  • 调整年轻代大小:适当调整年轻代的大小(Eden 区和 Survivor 区),避免过多对象晋升到老年代。
  • 使用 G1 GC 或其他垃圾回收器:一些现代的垃圾回收器,如 G1 GC,会通过优化垃圾回收策略来减少 Full GC 的影响,尤其是在大规模堆内存的环境中。
  • 减少对象的生命周期:减少在应用程序中创建大量短生命周期的对象,从而降低年轻代内存的压力,减少 Minor GC 频率,间接减少 Major GC 的频率。

e)监控 Major GC
开发人员可以通过各种工具来监控 JVM 中的垃圾回收活动,特别是 Major GC。例如:

  • JVM 日志:可以使用 -XX:+PrintGCDetails 和 -XX:+PrintGCDateStamps 等 JVM 参数来打印详细的垃圾回收日志,从中可以看到 Minor GC 和 Major GC 的发生情况
  • JVisualVM / JConsole:这些工具提供了图形化界面,可以实时查看 JVM 中的垃圾回收活动、堆的使用情况等信息。
  • GC 日志分析工具:可以使用 gcviewer 或其他 GC 日志分析工具来分析 Full GC 的频率和停顿时间。

f)Major GC 和 Minor GC 的区别

特性 Minor GC Major GC
回收的区域 主要回收年轻代(Young Generation)。 回收年轻代和老年代(Old Generation)。
触发条件 年轻代空间满,导致垃圾回收。 老年代空间满,或者发生对象晋升失败。
停顿时间 通常较短,影响较小。 通常较长,影响较大。
回收的对象 主要回收年轻代中的短生命周期对象。 回收老年代中的长生命周期对象。
发生频率 频繁,尤其是在对象创建较快的情况下。 相对较少,通常在内存压力较大时发生。

3. 永久代/元数据区
指内存的永久保存区域,主要存放 Class 和 Meta(元数据)的信息,Class 在被加载的时候被放入永久区域,它和和存放实例的区域不同,GC 不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的 Class 的增多而胀满,最终抛出 OOM 异常。

a)JAVA8 与元数据
在 Java8 中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代
元空间的本质和永久代类似,元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。类的元数据放入 native memory, 字符串池和类的静态变量放入 java 堆中,这样可以加载多少类的元数据就不再由MaxPermSize 控制, 而由系统的实际可用空间来控制。

标签:Major,对象,回收,GC,内存,JVM,运行
From: https://www.cnblogs.com/tim-zuo/p/18633723

相关文章

  • JVM内存模型、垃圾回收机制及简单调优方式
    JVM内存模型:1.方法区  用来存放类加载的信息,同时存放静态属性和方法(静态方法和普通方法)  jdk1.7之后,取消了方法区名称,改为元空间、方法区也叫元空间也叫永久区  方法区中的数据,可以被多线程共享。访问时会有数据共享的安全问题2.堆区  用来存放对象或数......
  • Kubernetes 为什么减少对 Docker 的依赖:容器运行时演进背后的技术考量
    1、概述在当今的技术领域,容器技术的崛起与发展离不开Docker和Kubernetes的紧密合作。Docker以其创新性的容器化技术,推动了容器在全球范围内的广泛应用,为开发者提供了从容器镜像构建、容器启动与管理到镜像分发等一站式服务。Kubernetes则专注于大规模容器的编排和自动......
  • Next.js 14 性能优化:从首屏加载到运行时优化的最佳实践
    在现代Web应用中,性能优化直接影响用户体验和业务转化。Next.js14提供了多种内置的性能优化特性,今天我们就来深入探讨如何充分利用这些特性,以及一些实用的优化技巧。图片和字体优化1.图片优化Next.js的Image组件供了强大的图片优化功能://components/OptimizedIm......
  • 3. JVM 内存区域
    JVM内存区域主要分为线程私有区域【程序计数器、虚拟机栈、本地方法栈】、线程共享区域【堆、方法区】、直接内存。线程私有数据区域生命周期与线程相同,依赖用户线程的启动/结束而创建/销毁(在HotspotVM内,每个线程都与操作系统的本地线程直接映射,因此这部分内存区......
  • VC++申请和释放内存问题(常发生在C code 转 VC++时)
    注意看,VC++环境下,用malloc申请内存空间的代码如下:编译显示成功,但在执行释放内存代码free(p);free(q);时报错。经过分析发现,p是结构体linkqueue指针,linkqueue结构体中有两个指针变量front,rear,在队列为空时,front和rear都指向头节点q.点击查看代码linkqueuep=(li......
  • memmove函数:内存重叠时拷贝
    最近测试遇到一个memcpy在x86和arm平台上拷贝字节时不一致的问题。出现拷贝是memcpy函数少量字节拷贝错误。分析参考:https://blog.csdn.net/shuidaoqingyi520/article/details/131669163在内存有重合的时候memcpy是不稳定的,要使用memmove函数。我于是自己写了个简单代码对比#i......
  • flask 异步任务celery中运行ipython或python repl出现阻塞
    问题场景:上传文件调用上传文件接口,异步任务解析文件,解析中需要执行python代码,此时会出现阻塞启动celery命令celery-Aapp.celeryworker-Pgevent-c1--loglevelINFO-Qnltable代码:importloggingimporttimeimportdatetimefromceleryimportshared_taskfr......
  • 1. JVM概述
    基本概念JVM是可运行Java代码的假想计算机,包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收,堆和一个存储方法域。JVM是运行在操作系统之上的,它与硬件没有直接的交互。运行过程我们都知道Java源文件,通过编译器,能够生产相应的.Class文件,也就是字节码文件,......
  • GO 学习笔记之五 编程(三)单元测试 ( VSCODE工具运行 )
    一、目的   当本地写好了一个go文件之后,希望通过单元测试来验证写的go文件中代码逻辑是否正确,减少后期发现问题成本。本案例介绍如何在VSCODE工具中触发执行和单点debug执行单元测试函数(注意:VSCODE工具有一个致命不好的点就是慢)二、编写单元测试  假设:当前业务逻辑go......
  • JavaScript中的数组和函数在内存分别是如何存储的?
    在JavaScript中,数组和函数在内存中的存储方式涉及到JavaScript的内存管理机制,特别是堆(Heap)和栈(Stack)的使用。虽然这些概念在底层实现上可能因JavaScript引擎(如V8,SpiderMonkey等)的不同而有所差异,但我们可以从一个高层次的视角来理解它们。1.数组在内存中的存储数组在JavaScript......