java内存回收浅谈

首先了解一下JVM

jvm分为栈区和堆区:

  1. 栈区主要存放,基本类型的变量数据对象的引用。对象本身存放在堆区或者常量池中(字符串常量存放在常量池中)
  2. 堆区主要存放:所有new出来的对象
  3. 静态域:存放静态成员(static定义的)
  4. 常量池:存放字符串常量和基本类型常量(加了final)
    *注意字符串如果是new出来的存放在堆区,如果编译期就创建好了(用""创建)才放到常量池中。

栈区的数据大小和生命周期是可以确定的,没用了会被清除,不涉及到gc。
堆区的对象涉及到GC,所以gc主要发生在堆区。

例如一个方法中创建了一个巨大对象,在方法中手动调用gc,因为这个方法还持有引用,内存不会回收这个对象。如果这个方法执行完了再回收这个对象,这个对象就会被回收。如果中间给这个值设置=null,这个原有对象的内存会被回收,因为栈引用对象发生了变化,不在引用原来内存区域,这块内存就会被回收。

20210430112143.jpg

gc一般回收

  • 没有根对象持有的对象
  • 弱引用和虚引用对象
  • 标记过的软引用对象

再来说下四种引用类型

  1. 强引用一般是不会被回收的
  2. 软引用描述是可能还有用,但非必要对象,内存不够的时候会第二次gc回收
  3. 弱引用只要gc了就会被回收
  4. 虚引用基本只要一创建就会被回收,我们使用意义不大

接下来我们说一下GC算法

核心是从root对象开始扫描对象

  1. 标记-清理
    先从上到下从左到右扫描整个内存块,将无用的标记,然后清除掉
    缺点:回收后的内存不连贯,造成大量内存碎片;回收内存多时效果差。
  2. 标记-整理
    先从上到下从左到右扫描整个内存块,将无用的内存标记,然后将无用的都移动到一端,有用的移动到另一端,最后直接将无用的清除掉。
    优点:避免了内存碎片
    缺点:效率低,回收越多越慢
  3. 复制算法
    将内存分为大小相同的AB区域,每次使用一块区域,区域满了对这个区域进行扫描,将存活的转移到另外一个区域,剩下的全部清除
    优点:快,不用遍历回收
    缺点:浪费内存

针对三种算发的优缺点,我们设计了分代算法

分代算法分

  1. 新生代(3复制算法)
    也可以分成伊甸园,S0,S1三个区域(8:1:1)
    新创建的对象会放到伊甸园区,等Eden区满了进行一次GC,将存活的对象复制到S0。
    多次重复GC后Eden的存活对象吧S0区域填满了后S0进行一次GC,还是利用复制算法将S0区域的存货对象复制到S1中,S1和S0交替使用,每次交替年拉+1,当年龄到了15后就可以转入老年代了。
  2. 老年代(2标记整理)
    进入老年代的对象有两种,一种是创建对象S0和S1切换存活了15次的,另外一种是新生代gc后还是内存不够的直接放老年代。(复制算法需要内存担保,老年代可以做内存担保,8:1:1如果新生代创建的对象gc一次存活超过10%的时候,可以直接把对象放到老年代)
    老年代采用标记整理算法,因为老年代的需要回收对象很少了。
  • 当老年代还是放不下对象的时候 ,发生OOM
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容