⑦⑦. 谈谈你对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