JVM知识点总结

本文详细探讨了JVM的内存模型,包括栈内存溢出的情况、JVM的内存区域划分以及垃圾回收机制。讲解了新生代和老年代的GC过程,介绍了Java中的几种垃圾回收算法如标记清除、复制、标记整理和分代收集。同时,讨论了如何通过调优参数优化JVM,以及如何判断对象存活和避免内存泄漏。文章还涉及到了类加载器、双亲委派机制以及不同类型的引用。最后,提到了直接内存和JVM性能优化的相关知识点。
摘要由CSDN通过智能技术生成
	#  以下问题仅作为知识记录,有问题大家可以留言或私信一起讨论学习!

1. 什么情况下会发生栈内存溢出?

  1. 栈是线程私有的,栈的生命周期和线程是一样的,每一个方法执行的时候,都会创建一个栈帧,它包含了局部变量表,操作数栈,动态链接方法的出口等等。局部变量表又包含基本数据类型和对象的引用。

  2. 当线程请求超过虚拟机允许的最大深度的时候,就会报栈内存溢出。

​ 比如:方法递归调用的时候就会触发栈内存溢出。

​ 解决:

​ 可以通过调整参数来调整JVM的栈的大小。

2.说说JVM的内存模型?

在这里插入图片描述
JVM将虚拟机分为5大区域,主要是程序计数器、虚拟机栈、本地方法栈、堆、方法区。

  1. 程序计数器是线程私有的,非常小的内存空间,当前线程的一些行号的指示器,用来记录当前虚拟机正在执行的一些线程指令地址,同时不会发生内存溢出的情况

  2. 虚拟机栈也是线程私有的,每一个方法在执行的时候都会创建一个栈帧,存储的是局部变量表、操作数、动态链接、方法返回等信息。

  3. 本地方法栈的线程私有的,保存的是native的方法的相关信息。当JVM创建一个线程,调用一个native的方法之后,JVM不会为该方法在虚拟机中创建栈帧的,而是简单的动态链接,并直接调用这个方法。

  4. 堆是所有线程共享的最大块的内存,几乎所有对象的实例和数组都在堆上分配内存,所以这个区域会经常发生一些垃圾回收的操作。

  5. 方法区存放的是已被加载的类信息(类名等),常量、静态变量、即时编译器编译之后的代码数据。在JDK1.8中就不存在方法区了,而是叫元数据区,元数据区被分为两个部分,第一部分是加载类的信息,第二部分是运行时的一些常量池;加载类的信息被保存在元数据区中,运行中的常量池被保存在堆中。

3.JVM中一次完整的GC是什么样子的?对象如何晋升到老年代?

堆分为新生代和老年代,新生代又分为Eden区和幸存者区(Survivor),幸存者区(Survivor)又分为Survivor0(to)区和Survivor1(from)区,Survivor0:Survivor1:Eden = 1:1:8 ; 当Eden区空间满的时候,就会触发一次Minor GC(轻量级的GC)来收集新生代的垃圾,存活的对象就会被分配到幸存者(Survivor)区,幸存者区之间是采用复制算法来进行复制对象的。对于大对象来说,需要大量连续的内存空间,会直接被分配到老年区。如果对象在Eden区出生,并且经过一次​Minor GC之后,如果仍然存活,被分配到Survivor区的话,那么它的年龄会进行加一,按照计算年龄的方式,来确定对象存活的周期。此后每经过一次minor GC,并且存活下来,年龄就进行加一,当年龄达到15的时候,就会晋升到老年代,大对象除外,直接进入到老年代。当老年代满的时候,无法容纳更多对象,这个时候就会触发FULL GC,Major GC是发生在老年代的GC,用来清理老年代区的,经常会伴随着Minor GC进行垃圾回收。

4.聊一聊Java中的回收算法?

Java中有四种垃圾回收算法:

  1. 标记清除法

    1. 标记整理法
    2. 复制算法
    3. 分代收集算法

1.标记清除法

  1. 标记:利用可达性分析来遍历内存,把存活的对象和垃圾对象进行标记;

在这里插入图片描述

  1. 清除:再遍历一遍内存,把标记的垃圾对象进行回收。

在这里插入图片描述

**特点:**

1. 标记和清除两个过程都比较耗时,效率不高,
2. 标记和清除过后会产生大量的不连续的空间碎片,这样会导致程序运行的时候,需要分配大对象而找不到连续内存空间,不得不触发一次GC

**使用:**

CMS垃圾收集器

2.标记整理法

  1. 标记:利用可达性分析来遍历内存,把存活的对象和垃圾对象进行标记;
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201222211330197.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lvbmd4dWV6aGVu,size_16,color_FFFFFF,t_70#pic_center)
  1. 整理:将所有存活的对象向一端移动,边界以外的对象都会回收掉,把对象的存储空间进行整理。
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201222211342314.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lvbmd4dWV6aGVu,size_16,color_FFFFFF,t_70#pic_center)


  **特点:**

  适用于存活对象多,垃圾少这种情况,需要整理过程所消耗的时间成本比较高一些,不会产生空间碎片。

  **使用:**

  老年代Serial Old,Parallel Old

3.复制算法

​ 将内存中按照容量大小相等的两块内存,像新生代中的Survivor区,每次只使用其中一块

在这里插入图片描述

​ 当这一块使用完之后,还存活的对象就会转移到另一块,把它有序的进行整理,然后把使用过的内存空间进行移除。

在这里插入图片描述

特点:

​ 不会产生碎片空间,但是需要浪费一块相同大小的内存空间。空间利用率降低。

使用

​ Serial、ParNew、Parallell

4.分代收集算法

​ 根据对象的存活周期不同,把内存划分为几块。JAVA虚拟机里面就会分为新生代和老年代,新生代中如果大量对象被回收,和少量对象存活的话,它会采用复制算法,只需要付出少量对象的复制成本就可以完成垃圾收集。老年代因为对象的存活率比较高,没有额外的空间对他进行分配和担保,它会采用标记清除或者标记整理的算法来进行回收。

5.常用的调优参数

-Xms 和 -Xmx (-XX:InitialHeapSize 和 -XX:MaxHeapSize):指定JVM初始占用的堆内存和最大堆内存。
# JVM也是一个软件,也必须要获取本机的物理内存,然后JVM会负责管理向操作系统申请到的内存资源。JVM启动的时候会向操作系统申请 -Xms 设置的内存,JVM启动后运行一段时间,如果发现内存空间不足,会再次向操作系统申请内存。JVM能够获取到的最大堆内存是-Xmx设置的值。

-XX:NewSize 和 -Xmn(-XX:MaxNewSize):指定JVM启动时分配的新生代内存和新生代最大内存。

-XX:SurvivorRatio:设置新生代中1个Eden区与1个Survivor区的大小比值。
# 在hotspot虚拟机中,新生代 = 1个Eden + 2个Survivor。如果新生代内存是10M,SurvivorRatio=8,那么Eden区占8M,2个Survivor区各占1M。

-XX:NewRatio:指定老年代/新生代的堆内存比例。
# 在hotspot虚拟机中,堆内存 = 新生代 + 老年代。如果-XX:NewRatio=4 表示年轻代与年老代所占比值为1:4,年轻代占整个堆内存的1/5。
# 在设置了-XX:MaxNewSize(设置新生代的最大内存)的情况下,-XX:NewRatio的值会被忽略,
# 老年代的内存=堆内存 - 新生代内存。  
# 老年代的最大内存 = 堆内存 - 新生代 最大内存。

-XX:OldSize:设置JVM启动分配的老年代内存大小,类似于新生代内存的初始大小-XX:NewSize。

-XX:PermSize 和 -XX:MaxPermSize:指定JVM中的永久代(方法区)的大小。
# 永久代不属于堆内存,堆内存只包含新生代和老年代。

-XX:MaxTenuringThreshold:对象从年轻代晋升到老年代经过GC次数的虽大阈值。

6.垃圾回收之新生代垃圾收集器

JVM的运行模式:Client模式和Server模式

1.Serial收集器

​ 采用的是复制算法-单线程-Client模式

​ Serial收集器(-XX:+UseSerialGC,复制算法)

​ 单线程收集,进行垃圾收集时,必须暂停所有工作线程

​ 简单高效,Client模式下默认的年轻代收集器

在这里插入图片描述

2.ParNew收集器

​ 采用的是复制算法-多线程-Client模式

​ ParNew收集器(-XX:+UseParNewGC,复制算法)

​ 多线程收集,进行垃圾收集时,必须暂停所有工作线程

​ 单核执行效率不如Serial,在多核下执行才有优势

在这里插入图片描述

3.Parallel Scavenge收集器

采用的是复制算法-多线程-Server模式

Parallel Scavenge收集器(-XX:+UseParallelGC,复制算法)

比起关注用户线程停顿时间,更关注系统的吞吐量

在多核下执行才有优势,Server模式下默认的年轻代收集器

在这里插入图片描述

7.垃圾回收之老年代垃圾收集器

1.Serial Old收集器

​ 采用的是标记整理算法-单线程-Client模式

​ Serial Old收集器(-XX:+UseSerialOldGC,标记-整理算法)

​ 单线程收集,进行垃圾收集时,必须暂停所有工作线程

​ 简单高效,Client模式下默认的老年代收集器

在这里插入图片描述

2.Parallel Old收集器

​ 采用的是标记整理算法-多线程

​ Parallel Old收集器(-XX:+UseParallelOldGC,标记-整理算法)

​ 多线程,吞吐量优先

在这里插入图片描述

3.CMS收集器

采用的是标记清除算法-多线程

CMS收集器(-XX:+UseConcMarkSweepGC,标记-清除算法)

优点:

几乎可以和用户线程做到同时工作,本质上还是要STOP-THE WORLD,只是停顿时间短

如果在老年代中存活更多存活率高的对象,使用CMS收集器更合适。

收集流程:(一边掉垃圾一边打扫)

**初始标记:**stop-the-world,从垃圾回收的根对象开始,只是扫描和根对象有关联的对象并做标记。虽然暂停了所有的线程工作,但是停顿时间很短。

**并发标记:**并发追随标记,程序不会停顿

**并发预清理:**查找执行并发标记阶段从年轻代晋升到老年代的对象

**重新标记:**暂停虚拟机,扫描CMS堆中的剩余对象

**并发清理:**清理垃圾对象,程序不会停顿

**并发重置:**重置CMS收集器的数据结构

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值