小菜良记

一文理清JVM和GC(上)

2020-04-06  本文已影响0人  菜农曰

本文主要介绍JVM和GC解析
本文较长,分为上下篇(可收藏,勿吃尘)
如有需要,可以参考
如有帮助,不忘 点赞

一、前期预热

1)JVM内存体系

其中方法区被JVM中多个线程共享,比如类的静态常量就被存放在方法区,供类对象之间共享,虚拟机栈本地方法栈程序计数器是每个线程独立拥有的,不会与其他线程共享。所以Java在通过new创建一个类对象实例的时候,一方面会在虚拟机栈中创建一个对该对象的引用,另一方面会在堆上创建类对象的实例,然后将对象引用指向该对象的实例。对象引用存放在每一个方法对应的栈帧中。

图片来源于网上

2)JAVA8之后的JVM

从图中我们可以看出JAVA8的JVM 用元空间取代了永久代


---
--- ---

3)GC作用域

---

4)常见垃圾回收算法

JVM的实现一般不采用这种方式

---

缺点:
1. 每次对对象赋值时均要维护引用计数器,且计数器本身也有一定的消耗;
2. 较难处理循环引用;

Java 堆从GC的角度可以细分为:新生代(Eden区、From Survivor区 和 To Survivor区)和 老年代。
特点:
复制算法不会产生内存碎片,但会占用空间。用于新生代。

---
MinorGC的过程(复制 --> 清空 --> 互换)
  1. 复制: (Eden、SurvivorFrom 复制到 SurvivorTo,年龄加1)
    首先,当Eden区满的时候会触发第一次GC,把还活着的对象拷贝到SurvivorFrom区,当Eden区再次触发GC的时候会扫描Eden区域和From区域,对这两个区域进行垃圾回收,经过这次回收后还存活的对象,则直接复制到To区域(如果有对象的年龄已经到达了老年的标准,则复制到老年代区),同时把这些对象的年龄加1。
  2. 清空:(清空Eden、SurvivorFrom)
    清空Eden和SurvivorFrom中的对象,也即复制之后有交换,谁空谁是to。
  3. 互换:(SurvivorTo和SurvivorFrom 互换)
    最后,SurvivorTo和SurvivorFrom 互换,原SurvivorTo成为下一次GC是的SurvivorFrom区。

算法分成标记和清除两个阶段,先标记出要回收的对象,然后统一回收这些。
特点:
不会占用额外空间,但会扫描两次,耗时,容易产生碎片,用于老年代

---

优点:
没有内存碎片,可以利用bump
缺点:
需要移动对象的成本,用于老年代
原理:

  1. 标记:与标记清除一样


    ---

    2.压缩:再次扫描,并往一段滑动存活对象


    ---

二、正文接入

1)判断对象是否可回收

Java中,引用和对象是有关联的。如果要操作对象则必须用引用进行。
因此,很显然的一个方法就是通过引用计数来判断一个对象是否可以回收。简单来说就是给对象添加一个引用计数器。每当有一个地方引用它,计数器的值加1,每当有一个引用失效时,计数器的值减1。
任何时刻计数器值为0的对象就是不可能再被使用的,那么这个对象就是可回收对象。
缺点: 很难解决对象之间相互循环引用的问题

---

所谓“GC roots” 或者说tracing GC 的 "根集合" 就是一组必须活跃的引用。
基本思路就是通过一系列名为“GC Roots” 的对象作为起始点,从这个被称为GC Roots的对象开始向下搜索,如GC Roots没有任何引用链相连是,则说明此对象不可用。也即给定一个集合的引用作为根出发,通过引用关系

图片来源于网上

2)哪些可以做GCRoots对象

3)JVM的参数类型

4)查看JVM默认值

5)常用的配置参数

经典案例设置:
-Xms128m -Xmx4096m -Xss1024k -XX:Metaspacesize=512m -XX:+PrintCommandLineFlags -XX:PrintGCDetails -XX:UseSerialGC

初始化大小内存,默认为物理内存1/64
等价于 -XX:InitialHeapSize

最大分配内存,默认为物理内存1/4
等价于 -XX:MaxHeapSize

设置单个线程的大小,一般默认为5112K~1024K
等价于 -XX:ThreadStackSize

设置年轻代大小

设置元空间大小


---

输出详细的GC收集日志信息


---
---

设置新生代中eden和S0/S1空间的比例
默认:
-XX:SurvivorRatio=8 --> Eden:S0:S1=8:1:1
修改:
-XX:SurvivorRatio=4 --> Eden:S0:S1=4:1:1
SurvivorRatio值就是设置eden区的比例占多少,S0/S1相同

设置年轻代与老年代在堆结构的占比
默认
-XX:NewRatio=2 新生代占1,老年代占2,年轻代占整个堆的1/3
修改
-XX:NewRatio=4 新生代占1,老年代占4,年轻代占整个堆的1/5
NewRatio值就是设置老年代的占比,剩下的1给新生代

设置垃圾最大年龄
-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入老年代。对于老年代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象在年轻代的存活时间,增加年轻代被回收的概论。

6)强软弱虚

图片来源于网络
图片来源于网络
public static void main(String[] args) {
        Object o1 = new Object();   //默认为强引用
        Object o2 = o1;     //引用赋值
        o1 = null;          //置空 让垃圾收集
        System.gc();
        System.out.println(o1);     // null
        System.out.println(o2);     // java.lang.Object@1540e19d
    }
    public static void main(String[] args) {
        Object o1 = new Object();
        SoftReference softReference = new SoftReference(o1);
        o1 = null;
        System.gc();
        System.out.println(o1);
        System.out.println(softReference.get());
    }
    public static void main(String[] args) {
        Object o1 = new Object();
        WeakReference weakReference = new WeakReference(o1);
        o1 = null;
        System.gc();
        System.out.println(o1);                     //null
        System.out.println(weakReference.get());    //null
    }
public static void main(String[] args) {
        Object o1 = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        PhantomReference<Object> phantomReference = new PhantomReference<>(o1,referenceQueue);
        System.out.println(o1);                         //java.lang.Object@1540e19d
        System.out.println(phantomReference.get());     //null
        System.out.println(referenceQueue.poll());      //null
    }
public static void main(String[] args) {
        WeakHashMap<Integer,String> weakHashMap = new WeakHashMap<>();
        Integer key = new Integer(1);
        weakHashMap.put(key,"测试1");
        System.out.println(weakHashMap);    //{1=测试1}
        key=null;
        System.out.println(weakHashMap);    //{1=测试1}
        System.gc();
        System.out.println(weakHashMap+"\t"+weakHashMap.size());    //{} 0
    }
上一篇 下一篇

猜你喜欢

热点阅读