我是靠谱客的博主 听话帆布鞋,最近开发中收集的这篇文章主要介绍java 回收内存_Java内存回收,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Java内存回收

Java的GC机制是自动进行的,和C语言有些区别需要程序员自己保证内存的使用和回收。下面是小编分享的具体介绍,一起来看一下吧。

Java的内存分配和回收也主要在Java的堆上进行的,Java的堆中存储了大量的对象实例,所以Java的堆也叫GC堆。

下面主要说一下对于java堆的内存回收 。

什么样的内存可以回收

判断法1:引用计数

方法:每有一个引用指向这个对象,那么这个对象的引用计数+1,反之,每有一个引用改变了指向,那么他原来指向的对象引用计数-1,当引用计数为0的时候,这个对象也就不可能被使用了那么就可以被回收了

问题:可能会出现环状的引用,导致不可能被使用的对象永远不可能被回收

示例:

Class A {

A a;

Public static void main(String[] args){

A gc1 = new A();

A gc2 = new A();

Gc1.a = gc2;

Gc2.a = gc1;

Gc1= null;

Gc2 = null;

}

Gc1和gc2都被设置成null了,他们都应该被清理,但是因为gc1的a对象指向gc2,gc2的a对象指向gc1,导致他们的引用计数永远为1,但是他们都永远不可能被使用了,所以这种方法存在漏洞

判断2:可达性分析算法

方法:从一个叫做GC ROOTS的节点出发,所有能够到达的引用对象标记起来,直到走到完全没有引用的地方为止,这样从这个节点连起来的所有的点(引用链),构成的路线就是不可回收的,那么所有没有被到达过的对象均可以被回收

什么可以做GC ROOTS:虚拟机栈(栈帧中的本地变量表)中的引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象、本地方法栈中JNI引用的对象

这些对象的特点:不可变并且随时可能被用到,生命周期长

补充:可达性分析的算法,那么没有在引用链上的对象都一定会被清理吗?不一定。当运行可达性分析的算法之后,会对所有没有在引用链上的对象进行一次标记和筛选,筛选的条件为:该对象覆盖了finallize()方法(这个方法是GC的时候如果这个对象要被回收则执行的方法,但是在Thinking in java中不推荐用来处理收尾工作),并且这个方法没有被执行过,那么就会把这个对象放到一个低优先级队列中执行,也就是这个对象的最后抢救的机会,如果这个时候这个对象把自己和在引用链上的引用连了起来,那么他在执行完finallize方法之后,再次判断时就不会被清理,否则会在第二次可达性判断的时候直接清理(因为finallize已经执行过一次了),如果没有覆盖这个方法,那么对不起,再见

回收算法介绍:

回收算法1:标记清理(Mark——sweep)算法

标记所有需要回收对象,然后将他们清理回收

问题:会产生内存碎片

优点:不需要暂停所有线程(Stop the world)

回收算法2:复制

标记后,将所有不需要回收的对象全部复制到一个空的内存中,然后清理刚刚使用的内存块

问题:浪费资源,会有一些内存堆无法被使用

解决:用在新生代,新生代会有80%以上的对象经过一次GC就会死亡,因此采用Eden + Survivor * 2的办法,Eden = 8 * Survivor大小(HotSpot默认),那么每次使用一个Eden + 一个Survivor,然后进行复制清理的时候,清理Eden + Survivor中,然后将可用的对象复制到空闲的Survivor中,然后全部清空前面的使用区,然后使用Eden 和复制到的Survivor

又一个问题:如果Survivor不够怎么办?向老年代借空间,叫做分配担保,不够存放的`对象会通过分配担保进入老年代

问题:需要 stop the world

回收算法3:标记整理(Mark——compact)

标记后,将可用内存向一侧摆放,然后清理掉可用内存边缘外部的所有内存区域

优点:没有内存碎片的问题

问题:需要stop the world

回收算法4:分代收集

将堆分代(老年代、新生代),老年代采用标记整理、标记清理等方法,新生代采用复制方法。

为什么:因为老年代大部分对象是可用的,因此如果采用复制算法,虽然没有内存碎片,但是空间浪费大,而且大部分对象没有变化,而在新生代使用复制算法,可以牺牲很小的内存空间就获得较好的效率

HotSpot中内存回收算法

枚举根节点(GC ROOTs)

Java虚拟机采用准确式GC,有一个OOPmap来标记哪个位置有个对象,这样在查找引用链的时候可以较快的找齐所有的引用链

Safepoint

在OOPmap的协助下,这个可以快速且准确的完成枚举,但是问题就是导致这个oopmap变化的指令非常多,如果为每一条指令生成oopmap,那么会需要大量额外空间,因此采用在特定点的地方生成,这些点同时也是safepoint的点,那么当需要枚举根节点的时候,就让线程运行到这个地方再停止。

一种方法:先停止所有线程,然后再让没有到安全点的线程自己跑到安全点再停下来,基本不适用,抢先试中断

另一种方法:主动式中断,设置一个标记,在执行的时候去轮询,而需要中断的时候,直接将这个位置的内存设置不可达,那么线程就会进入一个自陷异常,就自己会中断

【Java内存回收】相关文章:

最后

以上就是听话帆布鞋为你收集整理的java 回收内存_Java内存回收的全部内容,希望文章能够帮你解决java 回收内存_Java内存回收所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部