JVM00_面试官对类加载器子系统、运行时数据区、内存分布、执行引擎的灵虚拷问,你能坚持到第几问?(十二)

⑦⑦. 谈谈你对finalize( )方法中虚拟机的状态?


①. 如果从所有的根节点都无法访问到某个对象,说明对象已经不再使用了。一般来说,此对象需要被回收,但事实上,也并非是"非死不可"的,这时候它们暂时处于"缓刑"阶段。一个无法触及的对象肯能在某一个条件下"复活"自己,如果这样,那么对它的回收就是不合理的。为此,定义虚拟机中的对象可能有三种状态。如下:(掌握)


可触及的:从根节点开始,可以到达这个对象


可复活的:对象的所有引用都被释放,但是对象有可能在finalize( )中复活


不可触及的: 对象的finalize( )被调用,并且没有复活,那么就会进入不可触及状态。不可触及的对象不可能被复活,因为finalize( )只会被调用一次


②. 以上3种状态中,是由于finalize( )方法的存在,进行的区分。只有对象不可触及才可以被回收


⑦⑧. System.gc()与Runtime.getRuntime().gc()区别


  • ①. 通过System.gc()或者Runtime.getRuntime().gc()的调用,会显式触发Full GC,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存


⑦⑨. 什么是内存泄漏?


  • ①. javadoc中对OutOfMemoryError的解释是,没有空闲内存,并且垃圾收集器也无法提供更多内存


  • ②. 说明Java虚拟机的堆内存不够。原因有二


Java虚拟机的堆内存设置不够(比如:可能存在内存泄漏问题;也很有可能就是堆的大小不合理,比如我们要处理比较可观的数据量,但是没有显式指定JVM堆大小或者指定数值偏小。我们可以通过参数一Xms、一Xmx来调整)


代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)


③. 这里面隐含着一层意思是,在抛出0utOfMemoryError之前,通常垃圾收集器会被触发,尽其所能去清理出空间。


例如:在引用机制分析中,涉及到JVM会去尝试回收软引用指向的对象等。


在java.nio.BIts.reserveMemory()方法中,我们能清楚的看到,System.gc()会被调用,以清理空间。


⑧0. 什么是内存溢出?


①. 也称作“存储渗漏”。严格来说,只有对象不会再被程序用到了,但是GC又不能回收他们的情况,才叫内存泄漏


②. 但实际情况很多时候一些不太好的实践(或疏忽)会导致对象的生命周期变得很长甚至导致OOM,也可以叫做宽泛意义上的“内存泄漏


③. 尽管内存泄漏并不会立刻引起程序崩溃,但是一旦发生内存泄漏,程序中的可用内存就会被逐步蚕食,直至耗尽所有内存,最终出现0utOfMemory异常,导致程序崩溃。


⑧①. Java中内存泄漏的8种情况


①.单例模式(单例的生命周期和应用程序是一样长的,所以单例程序中,如果持有对外部对象的引用的话,那么这个外部对象是不能被回收的,则会导致内存泄漏的产生。)


②. 一些提供close的资源未关闭导致内存泄漏 数据库连接( dataSourse. getConnection()),网络连接(socket)和io连接必须手动close,否则是不能被回收的。


③. 静态集合类(如HashMap、LinkedList等等。如果这些容器为静态的,那么它们的生命周期与JVM程序一致,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。简单而言,长生命周期的对象持有短生命周期对象的引用,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收)


④. 内部类持有外部类(内部类持有外部类,如果一个外部类的实例对象的方法返回了一个内部类的实例对象。这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持有外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄漏。)


⑤. 变量不合理的作用域(一般而言,一个变量的定义的作用范围大于其使用范围,很有可能会造成内存泄漏。另一方面,如果没有及时地把对象设置为null,很有可能导致内存泄漏的发生)


⑥. 改变哈希值


⑦. 缓存泄漏(内存泄漏的另一个常见来源是缓存,一旦你把对象引用放入到缓存中,他就很容易遗忘。比如:之前项目在一次上线的时候,应用启动奇慢直到夯死,就是因为代码中会加载一个表中的数据到缓存(内存)中,测试环境只有几百条数据,但是生产环境有几百万的数据)


⑧. 监听器和回调(内存泄漏另一个常见来源是监听器和其他回调,如果客户端在你实现的API中注册回调,却没有显式的取消,那么就会积聚)


//静态集合类
public class MemoryLeak {
    static List list = new ArrayList();

    public void oomTests() {
        Object obj = new Object();//局部变量
        list.add(obj);
    }
}
//变量不合理的作用域
public class UsingRandom {
     private String msg;
     public void receiveMsg(){
        //private String msg;
        readFromNet();// 从网络中接受数据保存到msg中
        saveDB();// 把msg保存到数据库中
        //msg = null;
     }
}
//改变哈希值
public class ChangeHashCode {
    public static void main(String[] args) {
        HashSet set = new HashSet();
        Person p1 = new Person(1001, "AA");
        Person p2 = new Person(1002, "BB");

        set.add(p1);
        set.add(p2);
        p1.name = "CC";
        set.remove(p1);
        System.out.println(set);//2个对象!
        
//        set.add(new Person(1001, "CC"));
//        System.out.println(set);
//        set.add(new Person(1001, "AA"));
//        System.out.println(set);

    }
}


⑧②. 什么情况下会导致stop the world


①. 可达性分析算法中枚举根节点(GC Roots)会导致所有Java执行线程停顿


②. 进行gc的时候会发生STW现象(调用finalize()方法的时候会暂停用户线程


③. System.gc( ) | 调用finalize( )方法。我们调用System.gc( ) 会触发Full gc


上一篇:阿里大鱼数据库存储方案


下一篇:spring integration同步数据库数据