java 内存结构是逻辑存储结构,与内存模型不是一个概念
jvm有三部分组成
- 堆,
- 方法区(其实也是堆,只不过是逻辑分区,元空间(使用直接内存),1.8以前叫永久代(以前实际上是与堆隔离开的,物理上连续空间))
- 栈(程序计数器、本地方法栈、虚拟机栈组成)
堆
-
由线程共享,存放 new 出来的对象,是垃圾回收器的主要工作区域。
方法区
线程共享,实际使用的是堆内存,存放已被加载的类的元数据(方法代码,方法名、返回值、访问权限等)、常量池、静态变量、即时编译器编译后的代码等信息,最后会在堆中创建一个Class对象,方法区中的元数据,可以通过Class对象访问,JDK 1.8 中方法区被元空间取代,使用直接内存。
不过元空间与永久代最大的区别在于:元空间不在虚拟机设置的内存中,而是使用本地内存
方法区的理解 :元空间、永久代是方法区具体的落地实现。方法区看作是一块独立于Java堆的内存空间,它主要是 用来存储所加载的类信息的。
栈
-
线程私有,分为 Java 虚拟机栈和本地方法栈,存放局部变量表、操作栈、动态链接、方法出口等信息,方法的执行对应着入栈到出栈的过程。
-
本地方法栈:native关键字,凡是被native修饰的方法,都会去调用底层的非java语言的库
-
程序计数器:程序执行的时候,程序计数器是有值的,其记录的是程序正在执行的字节码的地址
垃圾回收
垃圾回收主要针对堆中的对象,堆的细分结构如下
新生代 (eden survivor0 survivor1 )
老年代
元空间(方法区,类元数据信息、串常量池、静态变量)
-
发现无用的信息对象
-
回收被无用对象占用的内存空间,使空间再次可被程序使用
堆中内存分配比例
新生代 :老年代 1:2
新生代 Eden:survivor0 :survivor1 8:1:1
垃圾回收算法
垃圾回收主要发生在堆,主要是回收内存无用的对象,本质是产生连续空间供给其他对象使用
四种引用关系与垃圾回收(强软弱虚)
强引用: 如 Object object= new Object(); 一个对象具有强引用,就不会被垃圾回收器回收。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止
软引用:在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行第二次回收对象,用来描述一些还有用但并非必需的对象,使用SoftReference表示
弱引用:JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用WeakReference来表示
虚引用:这个对象被收集器回收时收到一个系统通知,最弱的一中引用关系,不能通过虚引用来取得一个对象实例,用PhantomReference表示
GC判断该对象是否被回收
引用计数: 对象被引用的时候,计数器加1,当计数器为0的时候代表对象可以被回收。
可达性分析: 从GC Roots向下搜索,也就是从根对象往下搜索,经过的地方为引用链,如果对象不在引用链,则代表可被回收
可达性分析的GC Roots
- 虚拟机栈局部变量表中引用的对象
- 方法区中类静态属性引用的对象、常量引用的对象
- 本地方法栈中JNI(native方法)引用的对象
以上这些根节点是垃圾收集器在进行可达性分析时的起始点,它会从这些根节点出发,沿着对象引用关系向下搜索,形成可达的对象图。如果一个对象无法从任何根节点通过引用链到达,则认为它是不可达的,可以被垃圾回收器当作垃圾来处理
三色标记算法(tri-color-marking)
三色标记算法(tri-color-marking),是一种常见的垃圾收集的标记算法,属于可达性分析算法的一部分,常用于垃圾收集器CMS和G1
三色标记算法将每个节点归纳分类为三类:白色节点、灰色节点和黑色节点。三色标记算法采用深度优先搜索的策略
- 白色:可达性分析初始阶段,每个节点初始颜色都是白色(默认的),表示该节点还没被GC扫描过。如果可达性分析结束之后,节点仍然是白色,这表示该节点没有被引用,正常情况下是可以被GC回收。
- 灰色:表示该节点至少还有一个引用节点未被扫描过,这样的节点会被标记成灰色节点。
- 黑色:GC扫描过的节点节点会被标记成黑色节点,黑色节点表示存活对象,GC是不能回收的。
此处标记算法详细图解,请参考文章三色标记算法
复制法
先暂停程序的运行,然后将所有存活的对象从当前的堆复制到另一个堆,没有被复制的全部都是垃圾,当对象被复制到新的堆的时候,它们是一个挨着一个的,所以新堆保证紧凑排列,然后就可以按照上面的方法简单的分配新的空间了
标记-清除算法
分为两个阶段,一个是标记阶段,这个阶段内,为每个对象更新标记位,检查对象是否死亡;第二个阶段是清除阶段,该阶段对死亡的对象进行清除,执行 GC 操作。
- 是可以解决循环引用的问题
- 必要时才回收(内存不足时)
- 会产生内存碎片
标记—整理法
标记-整理法是标记-清除法的一个改进版。同样,在标记阶段,该算法也将所有对象标记为存活和死亡两种状态;不同的是,在第二个阶段,该算法并没有直接对死亡的对象进行清理,而是将所有存活的对象整理一下,放到另一处空间,然后把剩下的所有对象全部清除。这样就达到了标记-整理的目的,不会产生内存碎片
分代算法
不同的对象生命周期是不一样的。因此,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率
- 在新生代,每次垃圾收集器都发现有大批对象死去,只有少量存活,采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
- 而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须“标记清除法或者标记整理算法进行回收。
详细了解jvm算法及优化:jvm详解包含垃圾回收以及jvm参数优化
GC安全点
Java虚拟机(JVM)中的垃圾回收(GC)安全点(Safe Point)是指程序执行时的一个特定位置,在这个位置上,所有线程都处于已知且一致的状态,此时JVM可以安全地进行垃圾回收或者其他操作
安全点选择
安全点的选定通常发生在以下几种情况下:
- 程序执行过程中遇到“同步块”(如MonitorEnter和MonitorExit指令)或者调用方法等“控制流转换”的地方。
- 当线程处于Idle状态,例如线程调用sleep、wait等方法暂停运行时。
- 执行JNI(Java Native Interface)函数返回时。
- 在循环次数较多的代码中,JVM会通过采用“Polling”机制周期性检查是否需要触发GC
简单来说,就是在执行过程中那些具有“天然”暂停特性的位置,以及可以通过主动探测方式快速达到暂停状态的位置,都会被设置为安全点。在这些安全点,JVM可以暂停所有线程,然后开始垃圾回收工作,确保在此期间不会发生对象引用关系的变化,从而保证了GC的正确性和安全性