1.2.6 GC (Garbage Collection垃圾回收)

本文围绕Java展开,介绍了内存泄露的原因,如静态类使用、资源连接未关闭、监听器未删除等。还分析了minor gc频繁和缓慢的原因,阐述了标记清除、复制、复制整理、分代收集四种GC算法,解释了GC概念、优点、原理及回收机制,探讨了Java内存泄漏情况。

1、java中内存泄露是啥,什么时候出现内存泄露?

java导致内存泄露的原因很明确:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。

1. 静态类的使用
诸如 HashMap、Vector 等集合类的静态使用最容易出现内存泄露,因为这些静态变量的生命周期和应用程序一致,所有的对象Object也不能被释放,因为他们也将一直被Vector等应用着。

private static Vector v = new Vector();  
    public void test(Vector v){     
        for (int i = 1; i<100; i++) {         
        Object o = new Object();         
        v.add(o);         
        o = null;     
    }
}

虚拟机栈中保存者 Vector 对象的引用 v 和 Object 对象的引用 o 。在 for 循环中,我们不断的生成新的对象,然后将其添加到 Vector 对象中,之后将 o 引用置空。
虽然我们将 o 引用置空,但当发生垃圾回收时,我们创建的 Object 对象也不能够被回收。因为垃圾回收在跟踪代码栈中的引用时会发现 v 引用,而继续往下跟踪就会发现 v 引用指向的内存空间中又存在指向 Object 对象的引用。
也就是说,尽管o 引用已经被置空,但是 Object 对象仍然存在其他的引用,是可以被访问到的,所以 GC 无法将其释放掉。如果在此循环之后, Object 对象对程序已经没有任何作用,那么我们就认为此 Java 程序发生了内存泄漏。

2. 资源连接的使用

各种资源连接包括数据库连接、网络连接、IO连接等没有显式调用close关闭,不被GC回收导致内存泄露。

3. 监听器的使用

监听器的使用,在释放对象的同时没有相应删除监听器的时候也可能导致内存泄露。

2、minor gc如果运行的很频繁,可能是什么原因引起的,minor gc如果运行的很慢,可能是什么原因引起的?

频繁的原因:

1、 新生代空间设置过小。

2、大部分 Eden 区中的对象都能被认为是垃圾 永远也不会被复制到 Survivor 区或者老年代空间 (产生了大多数朝夕生灭的对象)

慢的原因:

1、 新生代空间设置过大。

2、 对象引用链较长,进行可达性分析时间较长。

3、 新生代survivor区设置的比较小,清理后剩余的对象不能装进去需要移动到老年代,造成移动开销。

4、 内存分配(借内存)担保失败,由minor gc转化为full gc

5、 采用的垃圾收集器效率较低,比如新生代使用serial收集器

参考:https://www.nowcoder.com/questionTerminal/b3cd86f89d6c4b1ab54252b49a6bff57?orderByHotValue=1&page=1&onlyReference=false

3、阐述GC算法

GC算法分成四种:

标记清除算法:首先先标记,然后统一把标记的对象依次清除,缺点是CPU消耗大,极易出现内存碎片,所以一般用于老年代。

复制算法:把内存区域分成俩块,每次只使用其中一块,然后把还存活的对象放在另一块中,清空原先的块,这样的话不会出现内存碎片。新生代常用的。

复制整理:指针碰撞,将使用过的对象移动到内存的一段,不用的放在另一端。
分代收集:根据不同代的区别,使用符合不同代的算法。

简单来说minorGC发生在新生代,频繁而且需要开销小,所以采取复制算法。
老年代:对象相较于新生代gc不频繁且对象少,采取标记清除或者标记整理算法。

参考:https://www.nowcoder.com/questionTerminal/488c7d26c0704102b4efe331559cb29c?orderByHotValue=1&page=1&onlyReference=false

4、GC是什么? 为什么要有GC?

GC是垃圾收集器。Java 程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:  

System.gc() 
Runtime.getRuntime().gc() 

Java是由C++发展来的。

它摈弃了C++中一些繁琐容易出错的东西。其中有一条就是这个GC。

写C/C++程序,程序员定义了一个变量,就是在内存中开辟了一段相应的空间来存值。内存再大也是有限的,所以当程序不再需要使用某个变量的时候,就需要释放这个内存空间资源,好让别的变量来用它。在C/C++中,释放无用变量内存空间的事情要由程序员自己来解决。就是说当程序员认为变量没用了,就应当写一条代码,释放它占用的内存。这样才能最大程度地避免内存泄露和资源浪费。

但是这样显然是非常繁琐的。程序比较大,变量多的时候往往程序员就忘记释放内存或者在不该释放的时候释放内存了。而且释放内存这种事情,从开发角度说,不应当是程序员所应当关注的。程序员所要做的应该是实现所需要的程序功能,而不是耗费大量精力在内存的分配释放上。

Java有了GC,就不需要程序员去人工释放内存空间。当Java虚拟机发觉内存资源紧张的时候,就会自动地去清理无用变量所占用的内存空间。当然,如果需要,程序员可以在Java程序中显式地使用System.gc()来强制进行一次立即的内存清理。

因为显式声明是做堆内存全扫描,也就是 Full GC,是需要停止所有的活动的(Stop The World Collection),你的应用能承受这个吗?而其显示调用System.gc()只是给虚拟机一个建议,不一定会执行,因为System.gc()在一个优先级很低的线程中执行。 

参考:https://www.cnblogs.com/guweiwei/p/6641016.html

5、垃圾回收的优点和原理。并考虑2种回收机制

 1、  java的一个显著的特点就是引入了垃圾回收机制,使c++程序员最头痛的内存管理问题迎刃而解,它使得java管理员在编写程序的时候不需要考虑内存管理,因为有了垃圾回收机制;

  2、 java对象中不再有“作用域”的概念,只有对象的引用才有“作用域”。

  3、 垃圾回收机制可以有效的防治内存泄露,有效的使用可以使用的内存。

  4、 垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对

某个对象或所有对象进行垃圾回收。

两种回收机制:回收机制有分代复制垃圾回收标记垃圾回收增量垃圾回收。(具体可参考1.2.5中的几种垃圾回收算法)

6、java中会存在内存泄漏吗,请简单描述。

理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因);然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生。(重复)

7、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?(垃圾回收)

1对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。

       通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。

     2、可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。

参考:https://www.cnblogs.com/zhangxiaopeng/p/5001171.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值