JVM 内存分配和垃圾回收机制 第二节

JVM 运行时内存

Java堆从GC的角度还可以细分为:新生代(Eden**区FromSurvivor**区ToSurvivor**区)和老年

代。
在这里插入图片描述

1.新生代

是用来存放新生的对象。一般占据堆的1/3空间。由于频繁创建对象,所以新生代会频繁触发

MinorGC进行垃圾回收。新生代又分为Eden区、ServivorFrom、ServivorTo三个区。

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

2.老年代

主要存放应用程序中生命周期长的内存对象。
老年代的对象比较稳定,所以MajorGC不会频繁执行。在进行MajorGC前一般都先进行 了一次MinorGC,使得有新生代的对象晋身入老年代,导致空间不够用时才触发。当无法找到足 够大的连续空间分配给新创建的较大对象时也会提前触发一次MajorGC进行垃圾回收腾出空间。
    MajorGC采用标记清除算法:首先扫描一次所有老年代,标记出存活的对象,然后回收没有标记的对象。MajorGC的耗时比较长,因为要扫描再回收。MajorGC会产生内存碎片,为了减少内存损耗,我们一般需要进行合并或者标记出来方便下次直接分配。当老年代也满了装不下的时候,就会抛出OOM(OutofMemory)异常。

3.永久代

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

4.JAVA8与元数据

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

垃圾回收

1.如何判断对象可以回收

1.1 引用计数法

	每当有一个地方引用它时,计数器就加1,当引用失效时,计数器就减1;任何时刻计数器为0的对象就是不可能在被使用的.
    默认标记次数 = 15次,当标记 = 0,gc直接回收
对象被引用的话,就会 +1,然后放到 s0或者s1区,如果还是被频繁使用,那么会放入老年代中。
    给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器都为0的对象就是不再被使用的,垃圾收集器将回收该对象使用的内存。
    引用计数法优点:
引用计数收集器可以很快的执行,交织在程序运行中。对程序需要不被长时间打断的实时环境比较有利

1.2可达性分析算法

通过一系列被称为「GC Roots」的根对象作为起始节点集,从这些节点开始,通过引用关系向下搜寻,搜寻走过的路径称为「引用链」,如果某个对象到GC Roots没有任何引用链相连,就说明该对象不可达,即可以被回收

四种引用

一、强引用
只要某个对象与强引用关联,那么JVM在内存不足的情况下,宁愿抛出outOfMemoryError错误,也不会回收此类对象。
二、软引用(softReference)
    java中使用SoftRefence来表示软引用,如果某个对象与软引用关联,那么JVM只会在内存不足的情况下回收该对象。
三、弱引用(WeakReference)
    java中使用WeakReference来表示弱引用。如果某个对象与弱引用关联,那么当JVM在进行垃圾回收时,无论内存是否充足,都会回收此类对象。
四、虚引用 (PhantomReference)	
    主要配合ByteBuffer使用 java中使用PhantomReference来表示虚引用。虚引用,虚引用,引用就像形同虚设一样,就像某个对象没有引用与之关联一样。若某个对象与虚引用关联,那么在任何时候都可能被JVM回收掉。虚引用不能单独使用,必须配合引用队列一起使用。

2.垃圾回收算法

2.1标记清除

Mark Sweep
    速度较快
    会造成内存碎片

2.2 标记整理

Mark Compact
    速度慢
    没有内存碎片

2.3 复制

Copy
    不会有内存碎片
    需要占用两倍的内存空间

3.分代垃圾回收

		新生代																老年代
伊甸园(Eden)幸存区(surviver) From 幸存区(Surviver)TO			
1.对象首先分配在伊甸园区域
2.新生代空间不足时,触发minor gc,伊甸园和from存活的对象使用copy复制到to中,存活的对象年龄加1并且交换from to
3.minor GC 会引发stop the world,暂停其他的线程,等待垃圾回收,用户线程才恢复运行
4.当对象寿命超过阈值时,会晋升至老年代,最大寿命是154bit)
5.当老年代空间不足,会先尝试触发minor GC,如果之后空间仍然不足,那么会触发full GC,STW的时间更长            
            

3.1相关VM参数

4.垃圾回收器

4.4G1

使用场景
    同时注重吞吐量和低延迟,默认的暂停目标是200ms
    超大堆内存,会将堆划分为多个大小相等的Region
    整体是标记+整理算法,两个区域之间是复制算法
相关JVM参数
    -XX:+UseG1GC
    -XX:G1HeapRegionSize=size
    -XX:MaxGCPauseMillis=time

G1垃圾回收阶段

YoungCollection

YoungCollection+ConcurrentMark

MixedCollection

5.JVM有哪些垃圾回收算法?

1.复制算法(copying)
    将内存划分为等同的两块,存活的对象放到一块上,回收另一块对象
    特点:不会产生内存碎片,速度较慢,内存被压缩一般,存活对象增多,就大大降低了存储效率
2.标记-清除算法(Mark Sweep)
    清除被标记的对象,会产生内存碎片,会造成内存资源的浪费,但速度快
3.标记-整理算法 (Mark Compact)  
    将存活的对象放到一端,回收被标记的对象,不会造成内存碎片,速度较慢
4.分代收集算法
    根据对象存活的不同生命周期将内存分为不同的域,根据各自的特点使用不同的算法回收

6.JVM有哪些垃圾回收器?

新生代回收器:SerialParNewParallel Scavenge
	serial:(串行)单线程、复制算法,会STW,单线程垃圾收集效率高,仍然是Client模式下默认的垃圾回收器
    parNew:serial+多线程,复制算法,会STW,默认开启和CPU数目相同的线程数,可以通过-ParallelGCThread参数设置垃圾回收的线程数
	Parallel Scanvenge:多线程,复制算法,并行高效的,程序能达到一个可控的吞吐量(运行用户代码时间/用户运行代码时间+垃圾回收时间),它的自适应策略就是与ParNew一个重要区分        
老年代回收器:Serial OldParallel Old、CMS
	Serial Old:单线程标记整理算法,是Client模式下默认的垃圾回收器,CMS垃圾回收器的后备回收器
    Parallel old:多线程标记整理算法 ,在老年代提供吞吐量优先
    CMS:多线程标记清除算法,主要目标是实现垃圾回收最短的停顿时间
整堆回收器:G1
	基于标记+整理算法

新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;老年代回收器一般采用的是标记-整理的算法进行垃圾回收。

7.详细介绍一下CMS垃圾回收器?

多线程标记清除算法,主要目标是获取垃圾回收停顿时间,使用在老年代中
有四个阶段:
    初始标记:
    标记GC roots直接相连的对象,速度很快,会STW
    并发标记:
	和用户线程一起工作,进行GC roots的跟踪过程,不需要STW
    重新标记:
    为了修正并发标记期间,程序运行导致标记产生一部分对象的变动,会STW
    并发清除:
    清除GC roots不可达的对象,进行并发工作
  

8.简述分代垃圾回收器是怎么工作的?

分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。
新生代使用的是复制算法,新生代里有 3 个分区:EdenTo SurvivorFrom Survivor,它们的默认占比是 8:1:1,它的执行流程如下:
1.Eden + From Survivor 存活的对象放入 To Survivor 区;
2.清空 EdenFrom Survivor 分区;
3.From SurvivorTo Survivor 分区交换,From SurvivorTo SurvivorTo SurvivorFrom Survivor。
每次在 From SurvivorTo Survivor 移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代。
老生代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。以上这些循环往复就构成了整个分代垃圾回收的整体执行流程。

9.说一下JVM的调优工具?

JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具。
jconsole:用于对 JVM 中的内存、线程和类等进行监控;
jvisualvm:JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、监控内存的变化、gc 变化等。

10.常用的JVM调优的参数有哪些?

-Xms2g:初始化推大小为 2g;
-Xmx2g:堆最大内存为 2g;
-XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4-XX:SurvivorRatio=8:设置新生代 EdenSurvivor 比例为 8:2;
–XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;
-XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合;
-XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;
-XX:+PrintGC:开启打印 gc 信息;
-XX:+PrintGCDetails:打印 gc 详细信息。

11.永久代和元空间的区别?

1.永久代的JVM本身的大小是固定的,无法进行调整,而元空间使用的是直接内存,只受本机的内存限制,如果元空间可能溢出,可以使用-XX:MaxMetaspaceSize参数设置最大的元空间大小,默认值为unlimited
2.元空间存储的是元数据,不由MaxPermSize控制,而由实际可用空间控制,可以加载更多的类
3.    

12.什么是直接内存?

在java4新加入NIO类,引入了一种基于通道(Channel)与缓存区(Buffer)的I/O形式,它可以直接使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,这样提高性能,避免了Java堆中和Native堆之间来回复制数据,只受到本机内存和处理器内存大小的限制

13.深度拷贝和浅度拷贝的区别?

浅度拷贝:
    对于基本数据类型,复制相同的值
    对于引用数据类型,复制的是栈上所指向的地址值,所有对复制的数据进行修改,会改变原来的值
深度拷贝:
    对于基本数据类型,复制的是值
    对于引用数据类型,在堆中重新开辟一块空间,进行拷贝,对拷贝的数据进行修改,不会影响原来的数据
    
    为了不影响原有数据,将数据进行深度拷贝

14.如果对象的引用被置为null,垃圾回收器是否会直接释放对象的内存?

不会,置为null值,只是断开了与栈帧的引用关系,用户线程要到达安全点才会扫描对象的引用关系,在对象确认无法引用时,这个对象可被回收

15.内存溢出和内存泄漏的区别?

内存溢出(out of memory):内存空间不足时导致的
内存泄漏(memory leak):该释放的对象没有释放,使用容器保存元素的时候    

16.介绍一下G1垃圾回收器?

使用场景 java9默认垃圾回收器
基于标记+整理算法
同时注重吞吐量和低延迟,默认的暂停目标是200ms,非常精确控制停顿时间
超大堆内存,避免全区域进行垃圾收集,会将堆划分为多个大小固定的独立区域,后台有个优先级列表,优先回收垃圾最多的区域,确保能高效回收垃圾
两个区域之间是复制算法

17.System.gc()和Runtime.gc()会做什么事情?

都是用来提示JVM进行垃圾回收,但是否立即回收还是延迟回收由java虚拟机来决定。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

抹泪的知更鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值