[仁润云技术团队]JVM之GC与内存分配策略

458 阅读4分钟

当需要排查各种内存溢出,内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈的时候,我们需要对自动化的GC和内存分配实施必要的监控和调节。

实际上,程序计数器,虚拟机栈和本地方法栈是线程隔离的,每一个栈帧中分配的内存在类结构一定的情况下是固定的(这里不考虑JIT优化),因此,只有这几个区域无需考虑内存分配及回收问题,因为方法结束或者线程结束时内存自然被回收了。

Java堆及方法区则不一样,一个接口的多个实现类需求的内存不一样,一个方法中多个分支需要的内存也不一样,这部分内存的分配及回收都是动态的,GC关注的也是这部分内存。

对象存活吗?

引用计数法

给对象添加一个引用计数器,每当有一个地方引用它,那么计数器的值加1,引用失效计数器的值减1。任何时刻计数器为零的对象就是不可能被再度使用的。

主流的Java虚拟机中没有使用这个方法来管理内存。主要是它很难解决对象之间的相互循环引用的问题。

class GCObject {
    public Object instance = null;
}
public class GCDemo {
    public static void main(String[] args) {
        GCObject obj1 = new GCObject(); // 1
        GCObject obj2 = new GCObject(); // 2
        
		obj1.instance = obj2; // 3
        obj2.instance = obj1; // 4
        
        obj1 = null; // 5
        obj2 = null; // 6
    }
}

以上分为6个步骤:

  1. GCObject的实例1引用计数加1,为1
  2. GCObject的实例2引用计数加1,为1
  3. GCObject的实例2引用计数加1,为2
  4. GCObject的实例1引用计数加1,为2
  5. 栈帧中的obj1不再指向Java堆,GCObject的实例1引用计数减1,为1
  6. 栈帧中的obj2不再指向Java堆,GCObject的实例2引用计数减1,为1

至此,产生内存泄漏。

可达性分析法

目前主流的虚拟机都是采用该算法。

可以作为GC Roots的对象:

img

  • 虚拟机栈的栈帧的局部变量所引用的对象。
  • 方法区的静态变量和常量所引用的对象。
  • 本地方法栈JNI所引用的对象。

上图中的reference1,2,3都是GC Roots对象。虽然实例3,5相互引用(连通),但是GC Roots不可达,这就是GC要回收的垃圾对象。

谈谈引用

在JDK 1.2之前,Java中引用的定义:如果reference类型的数据中存储的值代表的是另一块内存的起始地址,就称这块内存代表一个引用。

但是这样很难描述一些引用的“强弱”关系。因为在一些系统的缓存功能中,有一些内存的收集释放需要更为的合理化。于是,引用被分为强引用,软引用,弱引用,虚引用4种。

  • 强引用,Object obj = new Object(); 这类引用如果存在那么GC永远不会回收这部分内存。
  • 软引用,在系统要发生内存溢出时,这些对象将会被GC。SoftReference类。
  • 弱引用,这些对象会存在到下一次GC之前(无论内存是否足够)。WeakReference 类。
  • 虚引用,我们无法通过虚引用来访问对象,唯一目的就是这个对象被GC之前会收到一个系统通知。PhantomReference

对象之死

在可达性算法中不可达对象并非一定被GC。对象被GC至少需要两次标记过程,第一次是判断是否有同GC Roots相连接的引用链,如果没有那么判断是否有必要执行finalize()

如果有必要执行的话,那么将该对象放置到F-Queue中,然后通过虚拟机创建的一个低优先级的Finalizer线程执行它。

如果在这个过程中(指被标记需要执行finalize 方法到内存被回收这个时间段之内),对象和任意一个GC Roots相关联,那么对象将会逃逸。

回收方法区

HotSpot中的永久代。 废弃常量以及无用的类。 重点关注无用的类:

  • 该类的所有实例被回收。
  • 加载该类的ClassLoader被回收。
  • 该类的Class对象没有被引用,我们无法通过反射访问该类的方法。

一些大量使用反射,动态代理,CGLib技术的框架以及OSGi这类频繁定义ClassLoader的场景需要虚拟机具备类卸载的功能,以保证永久代不会发生内存溢出。

欢迎关注:www.renrunyun.com