JAVA垃圾回收机制总结
2017-03-09 16:22
176 查看
java语言的特点是引入了垃圾回收机制,大大减轻了程序员的压力。java语言规范并没有规定JVM使用哪种垃圾回收机制算法。
首先 介绍下java内存
线程共享的是方法区和java堆,其中方法区存放静态变量,常量池,构造方法等,常量池中存放字符串常量和部分包装类,java堆中存放类的实例。
线程私有区是PC寄存器和java栈,本地方法栈,PC寄存器用来记录正在执行的虚拟机字节码地址,java栈中存放原始数据类型,数据引用。
1,引用计数算法.
就是统计指向java堆中实例化对象的引用,当引用为0时的时候就认为该对象可回收。
然而缺点也很明显,比如上文中的循环引用就会导致引用计数算法认为这两个实例化对象均无法回收(引用计数为1)
为了避免这种情况,我们引入了根搜索算法,从一个java堆中实例化对象开始,扫描与之相连的实例化对象,若有不可到达的实例化,我们认为其可以被回收。
然而该种方法容易导致内存被切割成一块块,当需要较大的内存块时可能出现问题。为了解决这个方法可以针对上面的方法整理内存,将其整理成一整块内存(如何整理的,这部分没细看)。
还有一种回收方法就是采用复制的方法。划分两片区域,一块用来存放对象,另一块用来放着,当存放对象的那块满了以后就将上面存活的对象给复制过来,然后在这块内存上工作,同时将之前的内存清空,当自己这块满了以后再复制回去,如此反复。
一般现在jvm的垃圾回收机制是将上面几种结合。
首先将java堆分为新生代,老年代和永久代。新生代又可以分成eden代和survivor0代和survivor1代。刚产生的对象是放在eden区中,当这个区块放满了以后就将其存活的部分复制到survivor0块中,并且将Edon区中的数据清空,等到survivor0满了就将其中的存活的数据放到survivor1中,清空survivor0,垃圾回收到了一定次数还未被回收的对象,就可以放到老年区。老年区一般采用整理内存的方式(较为稳定,不会有频繁的gc),新生代一般采取复制的方法。
永久代用来存放代码,等一些基本不改变的数据。
需要注意的是由于垃圾回收的线程优先级较低,调用System.gc()并不会立刻使得该对象回收,当回收的时候会调用finalize()方法,所以我们不能指望通过调用system.gc()来指定什么时候进行垃圾回收。
首先 介绍下java内存
线程共享的是方法区和java堆,其中方法区存放静态变量,常量池,构造方法等,常量池中存放字符串常量和部分包装类,java堆中存放类的实例。
线程私有区是PC寄存器和java栈,本地方法栈,PC寄存器用来记录正在执行的虚拟机字节码地址,java栈中存放原始数据类型,数据引用。
1,引用计数算法.
就是统计指向java堆中实例化对象的引用,当引用为0时的时候就认为该对象可回收。
class object{ public object next; } public class test1 { public test1(){ object o1=new object();//工作栈中创建一个o1引用指向java堆中的o1实例,o1实例的引用计数+1 object o2=new object();//工作栈中创建一个o2引用指向java堆中的o2实例,o2实例的引用计数+1 o1.next=o2;//o2实例的引用计数+1 o2.next=o1;//o1实例的引用计数+1 o1=null;//工作栈中的引用不指向o1实例,o1实例的引用计数-1 o2=null;//工作栈中的引用不指向o2实例,o2实例的引用计数-1 } public static void main(String[] args) { new test1(); } }
然而缺点也很明显,比如上文中的循环引用就会导致引用计数算法认为这两个实例化对象均无法回收(引用计数为1)
为了避免这种情况,我们引入了根搜索算法,从一个java堆中实例化对象开始,扫描与之相连的实例化对象,若有不可到达的实例化,我们认为其可以被回收。
然而该种方法容易导致内存被切割成一块块,当需要较大的内存块时可能出现问题。为了解决这个方法可以针对上面的方法整理内存,将其整理成一整块内存(如何整理的,这部分没细看)。
还有一种回收方法就是采用复制的方法。划分两片区域,一块用来存放对象,另一块用来放着,当存放对象的那块满了以后就将上面存活的对象给复制过来,然后在这块内存上工作,同时将之前的内存清空,当自己这块满了以后再复制回去,如此反复。
一般现在jvm的垃圾回收机制是将上面几种结合。
首先将java堆分为新生代,老年代和永久代。新生代又可以分成eden代和survivor0代和survivor1代。刚产生的对象是放在eden区中,当这个区块放满了以后就将其存活的部分复制到survivor0块中,并且将Edon区中的数据清空,等到survivor0满了就将其中的存活的数据放到survivor1中,清空survivor0,垃圾回收到了一定次数还未被回收的对象,就可以放到老年区。老年区一般采用整理内存的方式(较为稳定,不会有频繁的gc),新生代一般采取复制的方法。
永久代用来存放代码,等一些基本不改变的数据。
需要注意的是由于垃圾回收的线程优先级较低,调用System.gc()并不会立刻使得该对象回收,当回收的时候会调用finalize()方法,所以我们不能指望通过调用system.gc()来指定什么时候进行垃圾回收。
相关文章推荐
- Java垃圾回收机制【经典总结】
- Java GC(垃圾回收)机制知识总结
- Java的垃圾回收机制总结
- java垃圾回收机制(学习总结)
- Java内存回收(垃圾回收)机制总结
- JAVA垃圾回收机制总结
- 总结: 十分钟理解 Java 对象生存期与JVM垃圾回收机制
- Java基础知识总结之垃圾回收机制
- JAVA 内存管理总结:内存泄露、数据存储、垃圾回收机制一网打尽!
- JAVA 内存管理总结:内存泄露、数据存储、垃圾回收机制一网打尽!
- 第十三天 :关于java中垃圾回收机制的总结
- JVM垃圾回收机制总结(6) :透视Java的GC特性
- java jvm gc 垃圾回收机制 总结
- Java垃圾回收机制知识点总结
- JAVA 内存管理总结:内存泄露、数据存储、垃圾回收机制一网打尽!
- java的垃圾回收机制详解和调优
- 全面分析Java的垃圾回收机制
- Java与C#的垃圾回收机制
- java的垃圾回收机制详解和调优
- JVM详解之Java垃圾回收机制详解和调