JVM参数、GC垃圾收集器、引用类型、OOM相关问题

参考文献 1
参考文献 2

1 JVM参数

1.1 JVM参数类型

    1 标准参数,即在JVM的各个版本中基本不变的,相对比较稳定的参数
        -help
        -server -client
        -version -showversion
        -cp -classpath
    2 X参数,非标准化参数,变化比较小的参数
        -Xint:解释执行
        -Xcomp:第一次使用就编译成本地代码
        -Xmixed:混合模式,JVM自己来决定是否编译成本地代码,默认使用的就是混合模式
    3 XX参数,特点是非标准化参数,相对不稳定,主要用于JVM调优和Debug 重点掌握
        1、Boolean类型
        格式:-XX[±]其中±表示启用或者禁用name属性 比如:-XX:+UseConcMarkSweepGC表示启用CMS垃圾收集器,-XX:+UseG1GC表示启用G1垃圾收集器
        2、非Boolean类型
        非布尔类型包括了kv类型和jinfo举例(如何查看当前运行程序的配置)
        格式:-XX:=表示name属性的值是value 比如:-XX:MaxGCPauseMillis=500表示GC的最大停顿时间是500毫秒,-XX:GCTimeRatio=19 ;
查看运行时参数的值
    注意:-Xmx和-Xms表示设置JVM的最大内存和最小内存,它们不是X参数,而是XX参数,-Xmx等价于-XX:MaxHeapSize,-Xms等价于-XX:InitialHeapSize;-Xss设置堆栈,也是XX参数,等价于-XX:ThreadStackSize

如何查看正在运行的程序他的某个JVM参数是否开启?具体值是多少?
    jps命令:查看后台正在运行的Java进程;
    jinfo命令:查看当前运行程序的各种信息;

XX参数Boolen型demo:
    从运行结果看出:当前程序没有开启JVM的PrintGCDetails参数,注意:IDEA支持cmd操作,这个demo在这个窗口中的进行和在cmd中进行是一样的。
在这里插入图片描述那我们通过IDEA给当前程序加上这个JVM参数:
在这里插入图片描述再次在cmd中查看,可看出参数已经设置
在这里插入图片描述JVM XX参数的KV类型demo:
在这里插入图片描述通过IDEA进行设置:
在这里插入图片描述更改后的结果
在这里插入图片描述

1.2 参数调优

    -Xss规定了每个线程堆栈的大小。一般情况下256K是足够了。影响了此进程中并发线程数大小。
    -Xms初始的Heap的大小。
    -Xmx最大Heap的大小。
    -Xmn设置年轻代大小:一般采用默认值就好
    在很多情况下,-Xms和-Xmx设置成一样的。这么设置,是因为当Heap不够用时,会发生内存抖动,影响程序运行稳定性。
    初始的堆内存大小为总内存的1/64;最大堆内存大小为总内存的1/4;
JVM调优查看默认初始值
在这里插入图片描述在这里插入图片描述JVM中常用参数:
在这里插入图片描述
在这里插入图片描述在这里穿插两个知识点
2.永久代和方法区的关系
    涉及到内存模型时,往往会提到永久代,那么它和方法区又是什么关系呢?《Java虚拟机规范》只是规定了有方法区这么个概念和它的作用,并没有规定如何去实现它。那么,在不同的 JVM 上方法区的实现肯定是不同的了。 同时大多数用的JVM都是Sun公司的HotSpot。在HotSpot上把GC分代收集扩展至方法区,或者说使用永久代来实现方法区。因此,我们得到了结论,永久代是HotSpot的概念,方法区是Java虚拟机规范中的定义,是一种规范,而永久代是一种实现,一个是标准一个是实现。其他的虚拟机实现并没有永久带这一说法。在1.7之前在(JDK1.2 ~ JDK6)的实现中,HotSpot 使用永久代实现方法区,HotSpot 使用 GC分代来实现方法区内存回收,可以使用如下参数来调节方法区的大小:

-XX:PermSize
方法区初始大小
-XX:MaxPermSize
方法区最大大小
超过这个值将会抛出OutOfMemoryError异常:java.lang.OutOfMemoryError: PermGen

3.元空间
    对于Java8, HotSpots取消了永久代,那么是不是也就没有方法区了呢?当然不是,方法区是一个规范,规范没变,它就一直在。那么取代永久代的就是元空间。它可永久代有什么不同的?存储位置不同,永久代物理是是堆的一部分,和新生代,老年代地址是连续的,而元空间不在JVM中,属于本地内存;存储内容不同,元空间存储类的元信息,静态变量和常量池等并入堆中。相当于永久代的数据被分到了堆和元空间中。

2 强引用、软引用、弱引用和虚引用

    在Java中垃圾回收器的运行是JVM操作的,但是我们仍然可以在一定程度上与垃圾回收器进行交互,其目的在于更好的帮助垃圾回收器管理好应用的内存。
1 强引用(StrongReference)
     当我们使用 new 这个关键字创建对象时创建出来的对象就是强引用(new出来对象为强引用) 如Object obj = new Object() 这个obj就是一个强引用了,如果一个对象具有强引用。垃圾回收器就不会回收有强引用的对象。如当jvm内存不足时,具备强引用的对象,虚拟机宁可会抛出OutOfMemoryError(内存空间不足),使程序终止,也不会靠垃圾回收器去回收该对象来解决内存。
2 软引用(SoftReference)
    如果一个对象只具有软引用,那就类似于可有可无的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。
软引用的作用:软引用可用来实现内存敏感的高速缓存。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
3 弱引用(WeakReference)
    如果一个对象只具有弱引用,那就类似于可有可物的生活用品。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
四、虚引用(PhantomReference)
    “虚引用”顾名思义,就是形同虚设,和其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有 虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。
ReferenceQueue queue = new ReferenceQueue ();
//虚引用对象
PhantomReference pr = new PhantomReference (object, queue);
    程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。设置虚引用的唯一目的就是,在对象被回收的时候会受到一个通知或添加进一步的处理。

3 OutOfMemory(OOM)&StackOverFlowError1

内存溢出
    申请内存,但是可分配的内存不足;
内存抖动
    内存抖动是指内存频繁地分配和回收,而频繁的gc会导致卡顿,严重时和内存泄漏一样会导致OOM。
内存泄漏
    有的对象不需要了,但是gc没办法将其回收;
未完待续。。。

其实JVM调参就是从默认值到期望值得一个调整过程

4 GC垃圾收集器

4.1 垃圾收集算法

1.Mark-Sweep(标记-清除)算法
    标记-清除算法分为两个阶段:标记阶段和清除阶段。标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。容易产生内存碎片,碎片太多可能会导致后续过程中需要为大对象分配空间时无法找到足够的空间而提前触发新的一次垃圾收集动作。
在这里插入图片描述
2.Mark-Compact(标记-整理)算法
    该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。相比垃圾清除算法慢。
在这里插入图片描述3.Copying(复制)算法
    它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉。空间浪费严重。
在这里插入图片描述4.Generational Collection(分代收集)算法
    一般情况下会分成新生代和老年代。老年代因为垃圾相对较少,一般采用复制清理和复制整理算法,新生代采用复制算法:E:S:S=8:1:1

4.2 垃圾收集器

怎么查看默认的垃圾回收器是什么?如何配置垃圾回收器? ·
在这里插入图片描述
    算法是方法论,垃圾收集器是具体实现。
在这里插入图片描述    图中展示了7种作用于不同分代的收集器,如果两个收集器之间存在连线,则说明它们可以搭配使用。虚拟机所处的区域则表示它是属于新生代还是老年代收集器。
    新生代收集器:Serial、ParNew、Parallel Scavenge
    老年代收集器:CMS、Serial Old、Parallel Old
    整堆收集器: G1
几个相关概念:
    并行收集:指多条垃圾收集线程并行工作,但此时用户线程仍处于等待状态。
    并发收集:指用户线程与垃圾收集线程同时工作(不一定是并行的可能会交替执行)。用户程序在继续运行,而垃圾收集程序运行在另一个CPU上。
    吞吐量:即CPU用于运行用户代码的时间与CPU总消耗时间的比值(吞吐量 = 运行用户代码时间 / ( 运行用户代码时间 + 垃圾收集时间 ))。例如:虚拟机共运行100分钟,垃圾收集器花掉1分钟,那么吞吐量就是99%
关于各个垃圾回收器的对比详细介绍,在这里就不反复造轮子了点击这里

4.3 垃圾收集器选择

在这里插入图片描述在这里插入图片描述

4.4 G1垃圾收集器的再讨论

G1垃圾收集器之前的收集器有什么特点?
    1 年轻代和老年代是相互独立且连续的区域;
    2 年轻代的收集器使用单E+S+S进行复制算法;
    3 老年代收集器必须扫描整个老年代;
    4 都是以少而快地执行GC为设计原则;
G1
    G1垃圾收集器是一款面向服务器端的垃圾收集器,在多处理器大存储量的环境中,实现高吞吐量的同时,尽可能满足垃圾回收暂停时间的要求,与CMS一样垃圾收集过程可与用户线程并发执行。
    G1的目标是取代CMS,相比CMS,以下几点更出色:
        G1是一个有整理过程的垃圾收集器,不回产生过多的空间碎片;
        G1的“Stop The world”更可控,G1在停顿时间上添加了预测机制,用户可以指定预期的停顿时间;
G1特点
在这里插入图片描述G1收集器存在的问题:

    Region不可能是孤立的,分配在Region中的对象可以与Java堆中的任意对象发生引用关系。在采用可达性分析算法来判断对象是否存活时,得扫描整个Java堆才能保证准确性。其他收集器也存在这种问题(G1更加突出而已)。会导致Minor GC效率下降。

G1收集器是如何解决上述问题的?
    G1的每个region都有一个Remember Set(Rset)这个数据结构,用来保存别的region的对象对我这个region的对象的引用,通过Remember Set我们可以找到哪些对象引用了当前region的对象

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值