跳至主要內容

19. GC

景天大约 3 分钟

JVM运行时数据区

image-20221025101040480
image-20221025101040480

程序计数器 程序计数器(Program Counter Register)是一块较小的内 存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。(每个线程都有自己的程序计数器,线程隔离)

Java虚拟机栈 它描述的是Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame )用于存储局部变量表、操作栈、动态链接、方法出口等信息。线程私有(线程隔离)

本地方法栈(线程私有) 本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。

Java堆 此内存区域的唯一目的就是存放对象,一个JVM实例只存在一个堆,堆内存的大小是可以调节的.堆内存是线程共享的。totalMemory 默认是系统64分之一 250M maxMemory 默认是系统的四分之一 4g

-Xms200m -Xmx300m

方法区(线程共享) 方法区(Method Area)与Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量 、静态变量等数据。

方法区是逻辑概念

  • 永久代
  • 元空间
image-20221025114142799
image-20221025114142799

内存管理

显式的内存管理(C/C++) 内存管理(内存的申请和释放)是程序开发者的职责 malloc() free() 常见问题: 内存泄漏:内存空间已经申请,使用完毕后未主动释放 野指针:使用了一个指针,但是该指针指向的内存空间 已经被free 隐式的内存管理(Java/C#) 内存的管理是由垃圾回收器自动管理的 优点:增加了程序的可靠性,减小了memory leak 缺点:无法控制GC的时间,耗费系统性能

GC

如何确定垃圾

引用计数算法

确定哪些对象已经变成了垃圾,最简单的算法就是引用计数法 给对象添加一个引用计数器 每当一个地方引用它时,计数器加1 每当引用失效时,计数器减少1 当计数器的数值为0时,也就是对象无法被引用时,表明对象不可在使用

但是这个算法存在一个致命的缺陷,无法解决循环引用的问题

为此,引入了另外一种根搜索算法。

根搜索算法

这个算法的基本思想是将一系列称为“GC Roots”的对象作为起始点 从这些节点开始向下搜索 搜索所走的路径称为引用链 当一个对象到所有的GC root之间没有任何引用链相连,时,就认为该对象变成了垃圾

image-20230223210058412
image-20230223210058412

GC Roots包含对象呢? 虚拟机栈中引用的对象 方法区中的静态属性引用的对象

如何回收垃圾

标记清除算法

image-20221025111136554
image-20221025111136554
image-20221025111147963
image-20221025111147963

标记复制算法

image-20221025111805455
image-20221025111805455
image-20221025111757163
image-20221025111757163

标记整理算法

image-20221025112108481
image-20221025112108481

分代收集算法

image-20221025113059119
image-20221025113059119

2个假说

  • 强分代假说
    • 熬过越多次垃圾收集过程的对象就越难以消亡。(简单理解就是越老的对象就具有”老而不死”的特性)
  • 弱分代假说
    • 弱分代假说(Weak Generational Hypothesis): 绝大多数对象都是朝生夕灭的.

什么时候回收垃圾

申请heap space失败后会触发GC回收

系统进入idle后一段时间会进行回收

主动调用GC进行回收 System.gc()