从头开始学JVM--------垃圾回收

一、新生代,老年代,永久代

        新生代:主要是用来存放新生的对象。如果出现频繁创建对象,那么这些对象会放入新生代。

                      新生代主要分别为 Eden区与Survivor区

        老年代:主要存放应用程序中生命周期长的内存对象。

        永久代:主要存放Class类的信息。可以粗略理解永久代就是方法区。GC一般不会在运行期间清理此处内存,所以Class文件变多的时候,很可能出现OOM。从上一节自己亲测的代码,也知道了JDK1.8以后,永久代被删除了,取而代之的是元空间。

二、常见垃圾回收算法

        一般来说,对于Java对象来说,某个对象无法被无法被访问到,或者说这个对象不可达的时候,此对象就可能会被GC回收。

        最简单的就是"标记-清除算法",首先标记处所有要被回收的对象,在标记完成后统一回收。缺点是效率差,会产生很多不连续的内存碎片。

        进阶版"标记-整理算法",把存活的对象移动到一端,然后清除掉边界以外的内存。

        新生代的 "复制算法"。把内存分为左右两块,当左边一块使用完毕后,把左边内存中还存活的对象全部复制到右边的这块内存上。然后把左边这块内存全部垃圾回收掉。

        机智的 "分代收集算法"。新生代因为对象频繁,生命周期短,所以使用"复制算法"。而老年代中对象生命周期很长,所以使用"标记-清理"、"标记-整理" 算法。

三、常见的垃圾回收器

        G1垃圾回收器,基于"标记-整理算法",因此不会产生内存碎片。

        GMS垃圾回收器,它注重响应速度,因此采取"标记-清除算法",所以会产生很多内存碎片,但是其响应速度快。

四、内存管理与回收策略

         有些大对象,可以直接将其配置到老年代中,防止在新生代中出现复制。因为在新生代中,可能使用的是"复制算法"。

         对于大对象的理解,就是一段连续分配的内存。比如字符串,或者数组。

         配置参数

-XX:PretenureSizeThreshold=<byte size> 命令超过这个字节大小的对象,直接分配在老年代

         另外的一种策略是,将长时间存活的对象,分配到老年代

         配置参数

-XX:MaxTenuringThreshold =15 当对象年龄为15岁的时候,会晋升到老年代

五、对象引用类型

         对象一般有4种不同的引用类型。

         强引用:不会被回收的内存。比如   Object obj = new Object();

         软引用:当内存不够用的时候,会被回收的内存。

         弱引用:生存到下次垃圾回收的内存。比如我们经常使用的ThreadLocal就用过这个。

         虚引用:仅仅是在这个对象在被垃圾回收的时候,收到一个系统通知。

         我最有印象的就是Thread这个类,它的源码中用到了ThreadLocal。每个Thread有一个ThreadLocalMap,每个ThreadLocalMap内部含有一个Entry[ ] 数组。这个Entry这种数据,它类似一个键值对,键就是我们熟悉的ThreadLocal。

         花了很长时间才明白,为什么ThreadLocal要设计为弱引用,实际上就是利用弱引用的特点。某个ThreadLocal对象是一个弱引用对象,它在下次垃圾回收的时候,内存被回收。那么,没有键,想访问到Entry节点的值,自然就不行了。所以,我们得手动写代码,判断ThreadLocal是否已经被GC回收。如果确实它已经被回收,那么我们要手动编写代码,清除掉已经访问不到的值,以防止内存泄露。可参考:ThreadLocal内存泄露

è¿éåå¾çæè¿°

         通过JDK源码,学习如何使用弱引用。下面是Thread.ThreadMap内部的Entry源码,它教了如何让某个类成为弱引用对象,我们可以依葫芦画瓢,其它类型的引用的使用也可以举一反三了。

         在以后的编码中,如果我们希望某些对象要被及时回收,可以继承这个WeakReference等类。

       static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;
 
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

 

posted @ 2022-07-17 12:14  小大宇  阅读(77)  评论(0编辑  收藏  举报