内存泄漏和内存溢出,安全点与安全区域

1.内存溢出: 

程序分配到了10MB内存,但运行过程中产生了11MB数据写入到该空间,这叫做内存溢出。

2.内存泄露:

 你在程序中申请了一块内存,使用了之后之后不会再使用,但是没有释放,而JVM的GC机制也无法回收这块区域,此时就可以被称为内存泄漏。好比程序中开了一个流对象,使用完成之后没手动关闭,GC机制也无法回收它,这种情况就是内存泄露。

3.关于内存泄漏

1. static字段引起的内存泄漏

大量使用static字段会潜在的导致内存泄漏,在Java中,静态字段通常拥有与整个应用程序相匹配的生命周期。

解决办法:最大限度的减少静态变量的使用;单例模式时,依赖于延迟加载对象而不是立即加载的方式(即采用懒汉模式,而不是饿汉模式)

2. 未关闭的资源导致内存泄漏

每当创建连接或者打开流时,JVM都会为这些资源分配内存。如果没有关闭连接,会导致持续占有内存。在任意情况下,资源留下的开放连接都会消耗内存,如果不处理,就会降低性能,甚至OOM。

解决办法:使用finally块关闭资源;关闭资源的代码,不应该有异常;JDK1.7之后,可以使用太try-with-resource块。

3. 不正确的equals()和hashCode()

在HashMap和HashSet这种集合中,常常用到equal()和hashCode()来比较对象,如果重写不合理,将会成为潜在的内存泄漏问题。

解决办法:用最佳的方式重写equals()和hashCode().

4. 引用了外部类的内部类

非静态内部类的初始化,总是需要外部类的实例;默认情况下,每个非静态内部类都包含对其外部类的隐式引用,如果我们在应用程序中使用这个内部类对象,那么即使在我们的外部类对象超出范围后,它也不会被垃圾收集器清除掉。

解决办法:如果内部类不需要访问外部类包含的类成员,可以转换为静态类。

5. finalize方法导致的内存泄漏

重写finalize()方法时,该类的对象不会立即被垃圾收集器收集,如果finalize()方法的代码有问题,那么会潜在的印发OOM;

解决办法:避免重写finalize()方法。


 

安全点和安全区域

当GC发生时,必然会出现程序停顿,也就是需要停止所有用户线程。但问题在于:用户线程停止的时机必须合理,不然在恢复线程后,有可能会导致最终的执行结果出现不一致,因此用户线程必然需要在一个安全的位置暂停。

而在JVM中,存在两个概念:安全点和安全区域,当用户线程执行到安全点或安全区域的代码处,此时发生停止是安全的,后续再次唤醒线程工作时,执行结果也不会因为线程暂停而受到任何影响

安全点

主动式中断(JVM采用的方式):不中断线程,而是设置一个标志,而后让每条线程执行时主动轮询这个标志,当一个线程到达安全点后,发现中断标志为true时就自己中断挂起。

安全区域:

安全区域是指在一段代码片段中,对象的引用关系不会发生变化,在这个区域中的任何位置开始GC都是安全的>。我们也可以把Safe Region看做足被扩展的 Safepoint。

你可能感兴趣的:(安全)