上后谈爱情

导航

 
  • 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维护对象的引用图,遍历有向图没有被标记的图像就可以被回收)
  • 压缩回收算法(带来性能损伤)
  • 复制回收算法(堆内存分为两块相同区域,任何时刻只有一个内存块被使用,内存耗尽将对象 紧凑复制到另外一块内存中 消除堆碎片但是增大的内存空间)
  • 按代价回收(大部分对象短暂的生命周期,较小对象较长生命周期 ,将经过多次收集存活的对象转移到高一级堆中,减小扫描次数)

 

3.finalize()方法:作用处理通过其他方式(C++ malloc 函数)开辟内存空间 或者垃圾回收器无法处理的对象

 

      通知回收器不能处理特性对象在回收之前进行资源的释放,特性对象 打开的文件资源或者通过调用C++中malloc函数分配的空间没有调用free函数释放。

 

调用finalize函数的对象只有在下一次的垃圾回收的动作时候才会真正释放回收,本次不会

 

 

 

  

 

二. 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).单例模式可能引起内存释放。

 

 

 

posted on 2017-06-06 10:55  上后谈爱情  阅读(267)  评论(0编辑  收藏  举报