java文件经过编译生产class文件,然后通过ClassLoader加载到内存中,然后经过检查,链接,初始化后,最终进入运行时状态.我们说的JVM内存模型就是基于运行时状态来说的,大致结构如下图所示:
主要分为两大区域:
java自带内存垃圾回收机制,那么垃圾回收机制又是怎么确认何为内存垃圾呢?下面介绍两种常见的垃圾定位方法
引用计数法就是,对象没被引用一次,则计数器加1,被解除引用一次则计数器减1,最后判断引用计数器的值是否为0,等于0,则表示为垃圾内存需要回收,否则不回收,但是这个会造成一个问题,那就是循环引用的对象,不会被判定为垃圾,比如A引用B,B引用C,C引用A,此时这三个对象并没有被其他对象引用,应该被回收,但是各自的引用计数器都不等于0,所以并不常用
可达性分析法,凡是没有直接或间接被GC_Root引用的对象,则为垃圾对象,直接引用就是GC_Root直接指向某个对象,比如GC_Root引用A,间接引用就是GC_Root引用A,A引用B,B引用C,则B和C都间接被GC_Root引用.
一般一下几种情况就是GC_Root对象
垃圾回收由于目标内存的特点,一般会使用不同的垃圾回收算法,下面介绍常见的集中垃圾回收算法
标记清除法,顾名思义就是先遍历标记出垃圾内存,然后在遍历清除被标记的垃圾内存,这种算法简单,但是会造成内存的不连续,浪费了大量的空间(特别是有大量小的内存间隙的时候,经常出现有时候需要申请的内存比内存间隙大),所以一般不推荐使用这种算法
复制算法,就是将内存分为均等的两份,开始分配内存的时候使用一份,内存满了开始垃圾回收,也是先遍历标记垃圾内存,然后将不是垃圾内存的对象复制到另一份内存中,清除掉第一份内存,此时内存分配工作将转移到第二份内存中,由于是复制存在的内存,所以不会有内存不连续的问题,但是整体复制,耗时大增,特别是遇到生存周期长的大内存对象,会比较耗时,而且内存利用率也不高,始终会有一半的内存空闲
标记整理法,先遍历标记出垃圾对象,然后将保留对象复制到内存的另一端,再清楚掉区域意外的内存区域,解决了标记清除法内存不连续的问题,但是也要复制一部分对象,所以也会有一定的耗时,但是相比复制算法,提高了内存的利用率
分代算法,将内存分为年轻带和老年代,再根据各自特点分配不同的回收算法,比如我们程序中大部分对象生命周期都比较段,应该被快速回收,所以内存分配的时候优先分配到年轻代,然后经过一定周期的保留后移到老年代,或者对象太大直接分配到老年代.