JVM之垃圾回收机制

时间:2024-04-12 20:01:04

JAVA内存模型图

JVM之垃圾回收机制

1程序计数器:记录当前线程所执行字节码的行号指示器

2虚拟机栈(Stack):存放了当前线程调用方法的局部变量表、操作数栈、动态链接、方法返回值等信息

 3、本地方法栈:为虚拟机使用的 Native 方法提供服务,后多与 JVM Stack 合并为一起

共享

4、 Java 堆(Heap):占据了虚拟机管理内存中最大的一块,唯一目的就是存放对象实例,存储对象的成员变量,

也是垃圾回收器主要管理的地方,故又称 GC 堆。

5、方法区:存储加载的类信息、常量区、静态变量JIT(即时编译器)处理后的数据等,类的信息包含类的版

本、字段、方法、接口等信息。需要注意是常量池就在方法区中。方法区因为总是存放不会轻易改变的内容,

故又被称之为“永久代”

提一下这个 Native 方法,指得就是 Java 程序调用了非 Java 代码,算是一种引入其它语言程序的接口 

6、垃圾回收器分为串行回收器、并行回收器、并发回收器,串行垃圾回收器单线程,效率低,并行和并发回收器
为多线程,但是并发回收器会造成程序阻塞,所以使用并行回收器进行垃圾回收,过程中会产生垃圾回收碎片,
会自动转换为串行垃圾回收器,清理完碎片,自动转换为并行垃圾回收器,不会对程序造成影响。

2堆和栈的区别

功能方面:堆是用来存放对象的,栈是用来执行程序的。

共享性:堆是线程共享的,栈是线程私有的。

空间大小:堆大小远远大于栈。

3JVM的垃圾回收机制

     1.jvvm 的垃圾回收机制后很多方法和垃圾回收器,我只了解分代管理法和清除标记法。

2、在 jvm 内存中有新生代、年老代、永生代,新生代中又包含 Eden(伊甸园)survival(幸存者),幸存者有两块

内存区域,但是使用时,仅一个区域可用,另一块幸存者内存区必须为空。

3、当创建对象时,会首先在 Eden 中开辟新的空间,如果 Eden 的内存区域不够用,无法开辟新的内存空间,则

会对 Eden 进行扫描,然后标记。垃圾回收器此时会找出哪些内存在使用中,还有哪些不是。垃圾回收器要检查完所有的

对象,知道哪些有被引用,哪些没有。对需要清除的对象进行标记,清理垃圾对象,然后将保留的对象拷贝到 Survival

幸存者区域。

4、如果 Eden Survival 新生代内存区域全部存满,这时候对整个新生代内存区域进行扫描,

将需要清除的对象进行标记,进行清除,将其他对象拷贝到年老代,这种 GC,称之为 Young

GC.

5、如果年老代内存区域也存满,需要对整个内存区域进行扫描,对对象进行标记,清除新生代和年老代内存区域,

将垃圾对象清除,这种 GC,称之为 Full GC

6、垃圾回收器分为串行回收器、并行回收器、并发回收器,串行垃圾回收器单线程,效率低,并行和并发回收器

 

为多线程,但是并发回收器会造成程序阻塞,所以使用并行回收器进行垃圾回收,过程中会产生垃圾回收碎片,

会自动转换为串行垃圾回收器,清理完碎片,自动转换为并行垃圾回收器,不会对程序造成影响。

4. 说一下 JVM 有哪些垃圾回收算法

    标记-清除算法:标记无用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片。

标记-整理算法:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。

复制算法:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已

使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。

分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年

代采用标记整理算法。

5. 垃圾回收相关的 JVM 参数

·

-Xms / -Xmx — 堆的初始大小 / 堆的最大大小

·

-Xmn — 堆中年轻代的大小

·

-XX:-DisableExplicitGC — 让 System.gc()不产生任何作用

·

-XX:+PrintGCDetails — 打印 GC 的细节

·

-XX:+PrintGCDateStamps — 打印 GC 操作的时间戳

·

-XX:NewSize / XX:MaxNewSize — 设置新生代大小/新生代最大大小

-XX:NewRatio — 可以设置老生代和新生代的比例

·

-XX:PrintTenuringDistribution — 设置每次新生代 GC 后输出幸存者乐园中对象年龄的分布

·

-XX:InitialTenuringThreshold / -XX:MaxTenuringThreshold:设置老年代阀值的初始值和最大值

·

-XX:TargetSurvivorRatio:设置幸存区的目标使用率

6. GC 是什么为什么要有 GC

     GC 是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的

不稳定甚至崩溃,Java 提供的 GC 功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java 语

言没有提供释放已分配内存的显示操作方法。Java 程序员不用担心内存管理,因为垃圾收集器会自动进行管理。

要请求垃圾收集,可以调用下面的方法之一:System.gc() 或 Runtime.getRuntime().gc() ,但 JVM 可以屏蔽掉

显示的垃圾回收调用。

垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的

线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实

时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。在 Java 诞生初期,垃圾回收是 Java 最大的亮点之一,

因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今 Java 的垃圾回收机制已经成为被诟病的

东西。移动智能终端用户通常觉得 iOS 的系统比 Android 系统有更好的用户体验,其中一个深层次的原因就在于

Android 系统中垃圾回收的不可预知性。

补充:垃圾回收机制有很多种,包括:分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。

标准的 Java 进程既有栈又有堆。栈保存了原始型局部变量,堆保存了要创建的对象。Java 平台对

堆内存回收和再利用的基本算法被称为标记和清除,但是 Java 对其进行了改进,采用“分代式垃

圾收集”。这种方法会跟 Java 对象的生命周期将堆内存划分为不同的区域,在垃圾收集过程中,

可能会将对象移动到不同区域:

伊甸园(Eden):这是对象最初诞生的区域,并且对大多数对象来说,这里是它们唯一存

在过的区域。

幸存者乐园(Survivor):从伊甸园幸存下来的对象会被挪到这里。

终身颐养园(Tenured):这是足够老的幸存对象的归宿。年轻代收集(Minor-GC)过程

是不会触及这个地方的。当年轻代收集不能把对象放进终身颐养园时,就会触发一次完全

收集(Major-GC),这里可能还会牵扯到压缩,以便为大对象腾出足够的空间。北京积云教育大数据方向-面试话术总结 V1.0.2

7. jvm 内存优化

      对 JVM 内存的系统级的调优主要的目的是减少 GC 的频率和 Full GC 的次数,过多的 GC 和 Full GC 是会占用很多

的系统资源(主要是 CPU),影响系统的吞吐量。特别要关注 Full GC,因为它会对整个堆进行整理,导致 Full GC

一般由于以下几种情况:

旧生代空间不足

调优时尽量让对象在新生代 GC 时被回收、让对象在新生代多存活一段时间和不要创建过大的对象及数组避

免直接在旧生代创建对象

Pemanet Generation 空间不足

增大 Perm Gen 空间,避免太多静态对象

统计得到的 GC 后晋升到旧生代的平均大小大于旧生代剩余空间

控制好新生代和旧生代的比例

System.gc()被显示调用

垃圾回收不要手动触发,尽量依靠 JVM 自身的机制

调优手段主要是通过控制堆内存的各个部分的比例和 GC 策略来实现,下面来看看各部分比例不良设置会导致什

么后果

1). 新生代设置过小

一是新生代 GC 次数非常频繁,增大系统消耗;二是导致大对象直接进入旧生代,占据了旧生代剩余空间,

诱发 Full GC

2). 新生代设置过大

一是新生代设置过大会导致旧生代过小(堆总量一定),从而诱发 Full GC;二是新生代 GC 耗时大幅度增加

一般说来新生代占整个堆 1/3 比较合适

3). Survivor 设置过小

导致对象从 eden 直接到达旧生代,降低了在新生代的存活时间

4). Survivor 设置过大

导致 eden 过小,增加了 GC 频率

另外,通过-XX:MaxTenuringThreshold=n 来控制新生代存活时间,尽量让对象在新生代被回收

由内存管理和垃圾回收可知新生代和旧生代都有多种 GC 策略和组合搭配,选择这些策略对于我们这些开发人员

是个难题,JVM 提供两种较为简单的 GC 策略的设置方式

1). 吞吐量优先

JVM 以吞吐量为指标,自行选择相应的 GC 策略及控制新生代与旧生代的大小比例,来达到吞吐量指标。这个

值可由-XX:GCTimeRatio=n 来设置

2). 暂停时间优先

JVM 以暂停时间为指标,自行选择相应的 GC 策略及控制新生代与旧生代的大小比例,尽量保证每次 GC 造成

的应用停止时间都在指定的数值范围内完成。这个值可由-XX:MaxGCPauseRatio=n 来设置

堆设置:

-Xms:初始堆大小

-Xmx:最大堆大小

-XX:NewSize=n:设置年轻代大小

-XX:NewRatio=n:设置年轻代和年老代的比值。如:为 3,表示年轻代与年老代比值为 1:3,年轻代占整个年轻代

年老代和的 1/4

-XX:SurvivorRatio=n:年轻代中 Eden 区与两个 Survivor 区的比值。注意 Survivor 区有两个。如:3,表示 Eden:

Survivor=3:2,一个 Survivor 区占整个年轻代的 1/5

-XX:MaxPermSize=n:设置持久代大小

  帖子详解:https://blog.****.net/sun1021873926/article/details/78002118

8. 说一下 JVM 调优的工具

  JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监

控工具。

jconsole:用于对 JVM 中的内存、线程和类等进行监控;

jvisualvm:JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、监控内存的变化、gc 变化等。

9. ·常用的 JVM 调优的参数都有哪些

  -Xms2g:初始化推大小为 2g; 

-Xmx2g:堆最大内存为 2g;

-XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4;

-XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2;

-XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;

-XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合

-XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;

-XX:+PrintGC:开启打印 gc 信息;

-XX:+PrintGCDetails:打印 gc 详细信息。