-
1.垃圾回收器:
Java中垃圾回收一般都是在Java堆中进行,Java堆存放几乎Java中所有的对象,Java堆被叫做GC堆,Java垃圾一词,指的是没有任何变量去引用它,JVM认为其是垃圾信息,可以被回收, 垃圾回收器 使用 有向图来记录和管理内存中所有的对象。
垃圾回收器三项任务:①分配内存 ② 确保被引用对象不被错误的回收 ③ 回收再也没有变量引用的对象。
在JDK1.2 对引用进行扩充:强引用 、软引用、弱引用、虚引用
强引用:Object obj=new Object(), 只要强引用还存在,垃圾回收器不会回收被引用对象
-
2.垃圾回收算法:
垃圾回收通过一定算法进行计算出哪些对象是可以被回收:
- 引用计数算法:很难解决对象之间相互循环引用问题
给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1,当引用失效时,计数器值就减1,任何时刻计数器都为0的对象就是不可能再被使用的。 引用计数算法的实现简单,判定效率也很高,在大部分情况下它都是一个不错的选择,当JVM并没有选择这种算法来进行垃圾回收,主要原因是它很难解决对象之间的相互循环引用问题。
- 追踪回收算法:利用JVM维护有向图,从根节点遍历图同时对对象进行标记,遍历结束后没有被标记的对象就可以被回收,inalize()方法在对象空间被回收之前进行调用,这个对象逃脱被销毁最后一次机会finalize()方法让该对象 与引用链上任何对象建立关联关系。
- 复制回收算法:将堆内存平均分为两部分,任何时刻,只使用其中一块内存,当一块内在用完之后,将存活的对象复制到之外的内存中,将此内存进行clear 优点:垃圾回收同时对对象进行安排,避免了内存碎片,缺点:降低内存使用空间,内存调整过程中中断当前程序,降低程序的执行效率
- 按代价回收算法:对复制回收算法的进步:程序创建大部分对象生命周期很短,小部分对象生命周期较长: 将堆分成多个堆,每一个子堆视为新一代,先收集年幼对象,如果发现某个对象在多次收集过程存活,将其移动到高级堆。
3.是否通过通知JVM 进行垃圾回收:
由于垃圾回收器存在,Java语言本身没有显示释放内存的方法,开发人员不能够时实调用垃圾回收器对某个对象进行垃圾回收,但是通过System.gc()方法通知垃圾回收器进行回收,代价:执行会停止所有的程序响应,去单独检测是否有对象可以进行回收---不推荐频繁使用
4.垃圾回收的代码分析:
在使用代码分析,对内存分配策越明确之下的三点
① 对象优先进入Eden分配 ②大对象直接进入老年代 ③长期存活的对象将进入老年代
1 public class SlotGc{ 2 public static void main(String[] args){ 3 byte[] holder = new byte[32*1024*1024]; 4 System.gc(); 5 } 6 }
在JavaC编译之后采用如下的指令: Java-verbose:gc SlotGc:发现 32MB内存并没有完全释放 holder变量还在作用域中
修改:
1 public class SlotGc{ 2 public static void main(String[] args){ 3 { 4 byte[] holder = new byte[32*1024*1024]; 5 holder = null; 6 } 7 System.gc(); 8 }
首先确定一点:holder是否释放根本原因在于 局部变量表中Slot是否还存在 对holder对象组的引用
在第一次代码中 在holder作用域之外进行回收,但是在此之后并没有对局部变量表中Slot进行修改,保留原先值,所以并没有释放内存
在第二次将局部变量表中slot=null,回收器会将holder 之前引用对象进行全部回收
当然采用方式对holder引用对象进行回收,只要 对holder所占用的slot修改即可
1. 问题一:Java 垃圾回收机制 如何判断一个对象是否die?
JVM管理的堆中内存,几乎存放存放所有的对象实例,如果一个对象在程序中没有任何引用指向他,那么该内存对象可以被收回,因此将 没有任何引用指向此对象 说明这个对象是Die,是可以被回收的对象。Java中通过引用与对象进行关联,操作对象必须对此对象进行引用,一种最简单的办法通过引用计算的方法判断对象是否被回收,但是这种方法无法解决循环引用的问题。
垃圾回收器:回收的是无任何引用的对象占用的空间不是这个对象 。回收老的空间给新的对象进行使用。JVM通过。
System.gc() / Runtime.getRuntime().gc() 显示的通知JVM进行一次垃圾回收。事实真正的垃圾回收时间不可预料的,主要和线程抢占有关系。
注意:System.gc() 并不能JVM立即做出垃圾回收反应只是让垃圾回收能够更加的容易提前发生
2. 垃圾回收算法:
- 引用计数算法(利用对象中引用计算器--无法解决循环引用)
- Tracing 回收(利用JVM维护对象的引用图,遍历有向图没有被标记的图像就可以被回收)
- 压缩回收算法(带来性能损伤)
- 复制回收算法(堆内存分为两块相同区域,任何时刻只有一个内存块被使用,内存耗尽将对象 紧凑复制到另外一块内存中 消除堆碎片但是增大的内存空间)
- 按代价回收(大部分对象短暂的生命周期,较小对象较长生命周期 ,将经过多次收集存活的对象转移到高一级堆中,减小扫描次数)
二. Java的GC堆中垃圾引用垃圾回收机制,自动进行垃圾回收 为什么Java中还是存在内存泄漏问题?
Java中内存空间是否被回收两个标准: ① 对象赋予NULL,之后没有被使用过 ②对象赋予新值重新分配了内存。 内存泄漏有两种情形:堆中申请new的内存没有被释放(Java垃圾回收机制)②不在使用对象还有内存 这样垃圾回收机制无法保证对象被释放。经典实例:不断循环创建对象加入到Vector容器中 如下图:
Vector v=new Vector(); for(int i=0;i<10;i++) { Object o=new Object(); v.add(o); }
退出循环o作用域over 但是v使用这些对象 导致垃圾回收器无法回收o对象。
Java语言中 内存泄漏问题很多:主要以下方面:
1).静态的集合类:HashMap和Vector静态的容器,生命周期与程序一样长,那么其中不使用对象不会释放
不使用集合之后将其进行 clear
2)各种动态链接 数据库连接,网络连接和IO连接,显示的进行连接的关闭
3). 监听器
4).变量不合理作用域:定义范围大于其使用范围+没有及时将对象设置null 不使用对象没有设置成null
5).单例模式可能引起内存释放。