不多说,直接上干货!
首先,大家要搞清楚,java里的内存是怎么分配的。详细见
牛客网Java刷题知识点之内存的划分(寄存器、本地方法区、方法区、栈内存和堆内存)
哪些内存需要回收
其实,一般是对堆内存而言的。
垃圾回收算法过程
在Java语言中,GC(Garbage Collection)是一个非常重要的概念。它主要是回收程序中不再使用的内存。
对对象而言,如果没有任何变量去引用它,那么该对象将不可能被程序访问,因此可以认为它是垃圾信息,可被回收。只要有一个以上的变量引用该对象,该对象就不会被垃圾回收。
public class Test {
public static void main(String a) {
Integer i1 = new Integer ();
Integer i2 = new Integer ();
i2 = i1;
}
}
资源i2所占的内存是不可达的。
(1)引用计数法
原理:为每个对象配一个计数器,如果这个对象被引用,则计数器加1,计数器为0,则表示该对象没有任何引用指向它。
缺点:不可达的对象出现循环引用,它的引用计数器均不为0。
(2)标记清除算法
原理:先通过根节点标记所有可达对象,然后清除所有不可达对象,完成垃圾回收。
缺点:会造成空间碎片。
① 标记出所有需要回收的对象。
② 标记完成后,统一回收所有被标记的对象。
缺点是:
①:标记和收集的两个过程效率都不高。
②:标记清除后会产生大量的不连续的内存空间,空间碎片多了以后就无法分配大块的内存空间给大的对象使用。
(3)复制回收算法
原理:将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。
把堆内存分成两个大小相同的区域,在任何时刻,只有其中的一个区域被使用,直到这个区域的被消耗完为止,此时垃圾回收器会中断程序的执行,通过遍历的方式把所有活动的对象复制到另外一个区域中,在复制的过程中它们是紧挨着布置的,从而可以消耗内存碎片。当复制过程结束后程序会紧着运行,直到这块区域被使用完,然后采取上面的方法继续进行垃圾回收。
优点:可确保回收后的内存空间是没有空间碎片的。同时,在进行垃圾回收的同时对对象的布置也进行了安排,从而消耗了内存碎片。
缺点:将系统内存折半。对于指定大小的堆来说,需要两倍大小的内存空间,同时由于在内存调整的过程中要中断当前执行的程序,从而降低了程序的执行效率。
复制算法适合用于新生代,因为新生代存活对象少,垃圾对象多。因为在新生代,垃圾对象通常会多于存活对象,复制算法的效果会比较好。
(4)标记压缩回收算法
标记压缩算法是一种老年代的回收算法,老年代大部分都是存活对象。
它对所有可达对象做了一次标记,然后,将堆中所有的存活对象压缩到堆内存的一端,这样就会在堆中另外一端留出很大的一块空闲区域,之后,清理边界外所有的空间。这种方法既避免了碎片的产生,又不需要两块相同的内存空间。
(5)增量算法
如果一次性将所有的垃圾进行处理,需要造成系统长时间的停顿,那么就可以让垃圾收集线程和应用程序线程交替执行。每次垃圾收集线程只收集一小片区域的内存空间,接着切换到应用程序线程,依次反复,直到垃圾收集完成。
优点:由于在垃圾回收的过程中,间断的执行了应用程序代码,所以能减少系统的停顿时间,但是,因为线程切换和上下文切换的消耗,会使得垃圾回收的总体成本上升,造成系统吞吐量的下降。
(6)分代回收算法(非常重要)
根据垃圾回收对象的特性,使用合适的算法回收。比如,新生代使用复制算法,老年代使用标记压缩回收算法。
被标记需要清除对象的自我救赎
标记清除算法是如何解决循环引用的问题呢?
利用可达性分析。枚举根节点,看根节点与对象是否可达,不可达则判断其可被回收,即便有多个对象循环引用,如果不可达则一样要被回收,从此解决循环引用问题。
可达性分析(Reachability Analysis),这个算法的思想是通过一系列的称为“GC Roots”的对象作为起点,从这些起点开始往下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何的引用链,相连接时,则证明这个对象是不可引用的。
可以作为GC ROOT的对象可以包括以下几种:
1、虚拟机栈中引用的对象
2、方法区中类静态属性引用的变量
3、本地方法区中常量引用的变量
4、本地方法栈中JNI(及一般说的Native方法)引用的对象。
要注意的是,即使没有通过可达性分析的对象,也并非是“非死不可”。
第一轮筛选:如果对象在可达性分析中没有于GcROOT链相连,那么就需要进行第二轮筛选
第二轮筛选:对象有没有覆盖(override)过 finalize()函数,对象是否还没运行过finalize()函数。如果这连个条件都满足,
那么对象就会判断为有必要执行finalize()函数,并把这个对象放入到一个叫做F-Queue的队列中,
稍后GC会对这个队列中的对象进行第二次扫描,执行每个对象的finalize()函数,那么如果对象要在这里拯救自己——只要在finalize()函数中让自己重新与GcROOT的任何一个对象建立连接即可。
譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那么在这第二次筛选中就会将这个对象移出出“即将回收”的集合。
对象将根据存活的时间被分为:年轻代、年老代(Old Generation)、永久代
以下是Java堆内存分配:
(1)年轻代
对象被创建时,内存的分配首先发生在年轻代(大对象可以直接被创建在年老代),大部分的对象在创建后很快就不再使用,因此很快就变得不可达,于是被年轻代的GC机制清理掉,这个GC机制被称为Young GC。
注意:Young GC并不代表年轻代内存不足,事实上只表示在Eden区上的GC
年轻代可以分为3个区:Eden(伊甸园,亚当和夏娃偷吃禁果生娃娃的地方,用来表示内存首次分配的区域,再贴切不过了)和2个survivor区。
(2)年老代
对象如果在年轻代存活了足够长的时间而没有被清理掉(即在几次Young GC后存活了下来),则会被复制到年老代,年老代的空间一般比年轻代要大,能存放更多的对象,在年老代上发生GC的次数也比年轻代少。当老年代内存不足时,将执行Full GC
如果对象比较大(如大数组),Young空间不足,则大对象会直接分配到年老代上。
(3)永久代
也就是方法区,主要存储Class信息,和存放对象的堆区不同,GC不会再主程序运行期间对永久代进行清理。如果load很多class,就会有可能出现Permanent Generation space错误。
以下是GC机制:
(1)年轻代
收集算法:
1)绝大多数刚创建的对象会被分配在Eden区,其中的大多数对象很快就会消亡
2)当Eden区满的时候,执行Young GC,将消亡的对象清理掉,并将剩余的对象复制到一个存货区survivor0中(此时survivor1是空白的,两个survivor区总是有一个是空白的)
3)此后,每次Eden区满了,就执行一次Young GC,并将剩余存活的对象都添加到survivor0中
4)当survivor0也满的时候,会将其中仍然存活的对象放入survivor1中,如果survivor1放不下,会将多出来的放入年老区中。以后Eden区执行Young GC之后,就将剩余的对象添加到survivor1中(此时survivor0是空的)
5)当两个存货区切换了若干次(默认为15次)之后,仍然存活的对象将被复制到年老代。
(2)老年代
老年代存储的对象比年轻代多的多,而且不乏大对象,对老年代进行内存清理时,一般采用标记-整理方法,即标记出仍然存活的对象,将存活对象向一端移动,以保证内存的连续。
在发生Young GC的时候,虚拟机会检查每次进入老年代的大小是否大于老年代的剩余空间大小,如果大于,则触发一次Full GC。
(3)永久代
包括常量池中的常量回收、无用的类信息回收。
注意:
1)Young GC只收集年轻代的对象,Full GC收集所有堆上的对象,包括年轻代、年老代、永久代的对象
2)总而言之,就是分代分配、分代回收
3)System.gc()调用的是Full GC
垃圾回收器的分类(非常重要)
如下
垃圾回收器按分代划分
新生代串行收集器:
1.复制算法 2.单线程垃圾回收 3.独占式的垃圾回收(也就是,在串行收集器运行时,应用程序中的所有线程都停止工作,进行等待。Stop the world现象。)
老年代串行收集器:
1.标记压缩算法 2.单线程垃圾回收 3.独占式的垃圾回收
并行收集器:
并行收集器是工作在新生代的垃圾收集器,它只是简单的将串行回收器多想线程化。同时,它也是独占式的收集器。
新生代并行回收收集器:
1.复制算法 2.多线程 3.独占式
老年代并行回收收集器:
1.标记压缩算法 2.多线程 3.独占式
CMS收集器:它关注系统挺停顿时间。并发标记清除。它可以与用户同时运行,从而降低应用程序的停顿时间。
G1收集器:
G1收集器是目前最新的垃圾回收器,G1收集器的目标是作为一款服务端的垃圾收集器,它在吞吐量和停顿控制上,预期要优于CMS收集器。
与CMS收集器相比,G1收集器是基于标记-压缩算法的,因此,它不会产生空间碎片,也没有必要在收集之后,进行一次独占式的碎片整理工作。G1收集器还可以进行非常精确的停顿控制,它可以在开发人员在指定长度为M的时间段中,垃圾回收时间不超过N。
牛客网Java刷题知识点之垃圾回收算法过程、哪些内存需要回收、被标记需要清除对象的自我救赎、对象将根据存活的时间被分为:年轻代、年老代(Old Generation)、永久代、垃圾回收器的分类的更多相关文章
-
牛客网Java刷题知识点之为什么HashMap和HashSet区别
不多说,直接上干货! HashMap 和 HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的 ...
-
牛客网Java刷题知识点之为什么HashMap不支持线程的同步,不是线程安全的?如何实现HashMap的同步?
不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...
-
牛客网Java刷题知识点之Map的两种取值方式keySet和entrySet、HashMap 、Hashtable、TreeMap、LinkedHashMap、ConcurrentHashMap 、WeakHashMap
不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...
-
牛客网Java刷题知识点之ArrayList 、LinkedList 、Vector 的底层实现和区别
不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...
-
牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响
不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 ...
-
牛客网Java刷题知识点之UDP协议是否支持HTTP和HTTPS协议?为什么?TCP协议支持吗?
不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 ...
-
牛客网Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤
福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 Java全栈大联盟 ...
-
牛客网Java刷题知识点之Java 集合框架的构成、集合框架中的迭代器Iterator、集合框架中的集合接口Collection(List和Set)、集合框架中的Map集合
不多说,直接上干货! 集合框架中包含了大量集合接口.这些接口的实现类和操作它们的算法. 集合容器因为内部的数据结构不同,有多种具体容器. 不断的向上抽取,就形成了集合框架. Map是一次添加一对元素. ...
-
牛客网Java刷题知识点之泛型概念的提出、什么是泛型、泛型在集合中的应用、泛型类、泛型方法、泛型接口、泛型限定上限、泛型限定下限、 什么时候使用上限?泛型限定通配符的体现
不多说,直接上干货! 先来看个泛型概念提出的背景的例子. GenericDemo.java package zhouls.bigdata.DataFeatureSelection; import ja ...
随机推荐
-
Java FX中TreeView节点选中和双击事件监听
TreeItem<String> treeRoot = new TreeItem<String>("Root"); treeRoot.setExpanded ...
-
《html表格》
1.html表格 w3c School:http://www.jb51.net/w3school/html/html_tables.htm 2.<colgroup></colgrou ...
-
Go实现海量日志收集系统(二)
一篇文章主要是关于整体架构以及用到的软件的一些介绍,这一篇文章是对各个软件的使用介绍,当然这里主要是关于架构中我们agent的实现用到的内容 关于zookeeper+kafka 我们需要先把两者启动, ...
-
PAT1090:Highest Price in Supply Chain
1090. Highest Price in Supply Chain (25) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 C ...
-
mysql的学习笔记(五)
1.子查询,出现在其他SQL语句的SELECT子句 SELECT * FROM t1 WHERE col1=(SELECT col2 FROM t2); 第一个SELECT称为外层查询,第二个称为子查 ...
-
8-06. 畅通project之局部最小花费问题(35)(最小生成树_Prim)(ZJU_PAT)
题目链接:http://pat.zju.edu.cn/contests/ds/8-06 某地区经过对城镇交通状况的调查.得到现有城镇间高速道路的统计数据,并提出"畅通project" ...
-
Google Kickstart Round.B C. Diverse Subarray
这题又是万恶的线段树 maxx[j]存储的是 l = xxx, r = j的时候的答案 我们会让 l 从 1到n 的遍历中,查询线段树的[l, n]中最大的答案 因为query的下界是n,所以单次查询 ...
-
html5 canvas用图案填充形状
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
-
tf.square
tf.square square( x, name=None ) 功能说明: 计算张量对应元素平方 参数列表: 参数名 必选 类型 说明 x 是 张量 是 half, float32, float64 ...
-
Myeclipse更新SVNStatusSubscriber 时报告了错误。1 中的 0 个资源已经同步。
1.先确认SVN服务是否能连接,或权限. 方法:在项目目录下右键选择repo-browser 能打开就表示正常. 2.同样在项目目录下选择cleaup 选择下面3个选项 clean up workin ...