• 重读《深入理解Java虚拟机》二、Java如何分配和回收内存?Java垃圾收集器如何工作?


    线程私有的内存区域随用户线程的结束而回收,内存分配编译期已确定,内存分配和回收具有确定性。共享线程随虚拟机的启动、结束而建立和销毁,在运行期进行动态分配。垃圾收集器主要对共享内存区域(堆和方法区)进行垃圾收集回收。

    Java如何实现内存动态分配和内存垃圾的回收?

    1、哪些内存需要回收(垃圾收集器内存回收的对象)?已经“死亡”的对象,那如何判定对象已经“死亡”了?

         Java堆回收的内存:已经”死亡“的对象

         方法区回收的内存:废弃的常量和无用的类

    2、什么时候进行回收?什么情况下垃圾收集器自动回收内存?

    3、如何回收?Java虚拟机是如何实现内存回收的?

    (一)Java堆内如何判断对象已经“死亡”

    1、引用计数算法:

       算法思路:通过对象的引用计数器判断,引用的时候递增计数器,引用失效后递减计数器。

       缺点:难以解决循环引用问题

    2、可达性分析算法:

      算法思路:判断对象到GC Root节点是否存在引用链,如果不存在则说明对象不可用。

      缺点:(1)当GC Root点多的时候逐个检查消耗时间过多

               (2)进行分析的时候GC需要停顿,停顿所有Java执行线程。

       GC Root节点:主要存在全局性引用(常量,静态属性)、执行上下文(如栈帧的本地变量表)中,

       具体可作为GC Root节点的有:

                                1)虚拟机栈(栈帧内的本地变量表)中引用的对象

                                2)方法区内的静态属性和常量引用的对象

                                3)本地方法栈中本地方法引用的对象

                

    3、对象引用的划分

    引用类型

    特点和用途

    内存回收时机

    实现

    强引用

    操作引用对象。 不可回收 类似 Object boj=new Object();的引用

    软引用

    用来描述有用但非必需的对象,比强引用弱 第二次回收 SoftReference

    弱引用

    用来描述有用但非必需的对象,比软引用弱 下一次垃圾回收的时候,无论内存是否足够都进行回收。 WeakReference

    虚拟用

    实现对象在垃圾收集器回收的时候收到系统通知。最弱的引用关系 下一次垃圾回收的时候 PhantomReference

    (二)方法区内如何判断废弃的常量和无用的类?

    1、如何判定废弃的常量

         和堆内存对象的存活判断类似

    2、如何判定无用的类

       成为无用类的条件(同时满足这个三个条件):

      (1)所有实例对象都已经回收,Java堆中不存在该类的任何实例

      (2)加载该类的ClassLoader已经回收

      (3)类的Class信息不存在引用,不存在反射访问该类的方法

    (三)垃圾收集器如何回收内存?

    1、标记-清除算法

              (1)算法实现:

                  分为“标记”和“清除”两个阶段,首先标记出需要回收的对象,标记完成后统一回收被标记的对象。

             (2) 特点:

                    1)效率低

                    2)易产生大量不连续的内存碎片,内存空间碎片过多导致在分配大对象时候,没有足够的连续内存分配, 就有触发一起垃圾收集操作

    2、复制算法

             为了解决“标记-清除”算法的低效率问题,而提出的

             (1) 算法实现:

                 将内存分为两个大小相等的内存区域,一半用于分配内存,另一半暂时不用,也就是只使用内存中的一半。等到该一半内存用完了,不足以分配更多的内存的时候,将该一半内存区域内的还存活的对象复制到另一半,然后将之前占用的一半内存区域清空。

               (2)特点:

                     1)提升了效率,但是内存空间只使用了一半,属于用空间换效率

                     2)对象的存活率高的情况下,需要进行大量的复制操作,效率也会降低

    3、标记-整理算法

             根据老年代的特点,提出的算法

               (1)算法实现:

                          同“标记-清除”算法类似,分为“标记”和“整理”两个阶段,首先标记出需要回收的对象,标记完成后将存活的对象向一端移动,然后直接清理掉端边界以外的内存。

               (2)特点:

                      1)还是存在低效率的问题,标记过程和整理的过程效率低

    4、分代收集算法

                    根据对象存活周期的不同将内存划分为新生代和老年代,然后根据各个年代的特点采用最适当的收集算法。

                (1)算法实现:

    年代

    特点

    内存回收算法

    新生代 每次垃圾收集会有大批对象死去,只有少量对象存活 复制算法
    (只需要复制少量的存活对象)
    老年代 对象存活率高、没有额外的内存空间对它进行分配担保 标记-清理算法或者
    标记-整理算法

                 (2)特点

                      根据对象存活周期的长短,采用不同的算法

     

    (四)如何分配内存?(内存的分配策略)

      1、对象优先在Eden分配

      2、大对象(需要大量连续内存空间的对象)直接进入老年代

      3、长期存活的对象直接进入老年代

  • 相关阅读:
    swift中? ! weak unowned以及动态时语言理解
    线程状态---Day24
    线程安全---Day23
    线程---Day22
    异常---Day21(写得有错请指出,感谢)
    Java之路---Day18(List集合)
    Java之路---Day17(数据结构)
    Java之路---Day16(泛型)
    Hoeffding不等式证明
    事件绑定之.bind()
  • 原文地址:https://www.cnblogs.com/wshcn/p/6942129.html
Copyright © 2020-2023  润新知