Java 中会存在内存泄漏问题?

所谓内存泄露就是指一个不再被程序便用的对象或变量一直被占据在内存中。

Java 中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象变成了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉。

既然java有垃圾回收机制,为什么还会存在内存泄漏的问题呢?

无非,就是有些对象,无法被垃圾回收器处理,导致这些对象一直占用JVM内存,那不就导致内存泄漏了嘛。

由于 Java 使用有向图的方式进行垃圾回收管理,可以消除引用循环的问题 ,例如有两个对象 ,相互引用,
只要它们和根进程不可达的,那么GC也是可以回收它们的,例如下面的代码可以看到这种情况的内存回收。
import java. io.IOException; public class GarbageTest { public static void
main(String[] args) throws IOException { try { // TODO Auto-generated method
stub gcTest(); } catch (IOException e) { e.printStackTrace(); }
System.out.println("has exited gcTest!"); System.in.read(); System.in.read();
System.out.println("out begin gc!"); for (int i = 0; i < 100; i++) {
System.gc(); System.in.read(); System.in.read(); } } private static void
gcTest() throws IOException { System.in.read(); System.in.read(); Person p1 =
new Person(); System.in.read(); System.in.read(); Person p2 = new Person();
p1.setMate(p2); p2.setMate(p1); System.out.println("before exit gctest!");
System.in.read(); System.in.read(); System.gc(); System.out.println("exit
gctest!"); } private static class Person { byte[] data = new byte[20000000];
Person mate = null; public void setMate(Person other) { mate = other; } } }
Java 中的内存泄露的情况:
长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短室命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是
Java 中内存泄露的发室场景
,通俗地说,就是程序员可能创建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被垃圾回收器回收的,这就是 java
中可能出现内存泄露的情况。

例如,缓存系统,我们加载了一个对象放在缓存中 (例如放在一个全局map对象中),然后一直不再使用它,这个对象一值被缓存引用, 但却不再被便用。

检查 Java 中的内存泄露,一定要让程序将各种分支情况都完整执行到程序结束,然后看某个对象是否被使用过,如果没有,则才能判定这个对象属于内存泄露。

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

下面内容来自于网上
(主要特点就是清空堆栈中的某个元素,并不是彻底把它从数组中拿掉,而是把存储的总数减少,本人写得可以比这个好,在拿掉某个元素时,顺便也让它从数组中消失,将那个元素所在的位置的值设置为
null 即可)

我实在想不到比那个堆栈更经典的例子了,以致于我还要引用别人的例子,下面的例子不是我想到的,是书上看到的
,当然如果没有在书上看到,可能过一段时间我自己也想的到,可是那时我说是我自己想到的也没有人相信的。
public class Stack { private Object[] elements = new Object[10]; private int
size = 0; public void push(Object e) { ensureCapacity(); elements[size++] = e;
} public Object pop() { if (size == 0) throw new EmptyStackException(); return
elements[--size]; } private void ensureCapacity() { if (elements.length ==
size) { Object[] oldElements = elements; elements = new Object[2 *
elements.length + 1]; System.arraycopy(oldElements, 0, elements, 0, size); } } }
上面的原理应该很简单,假如堆钱加了10 个元素 ,然后全部弹出来
,虽然堆钱是空的,没有我们要的东西,但是这是个对象是无法回收的,这个才符合了内存泄露的两个条件 无用,无法回收。
但是就是存在这样的东西也不一定会导致什么样的后果 ,如果这个堆钱用的比较少,也就浪费了几个 K 内存而己,反正我们 的内存都上 G
了,哪里会有什么影响,再说这个东西很快就会被回收的,有什么关系。 下面看两个例子。
class Bad { public static Stack s = new Stack(); static { s.push(new
Object()); s.pop(); //这里有一个对象发生内存泄露 s.push(new Object());//上面的对象可以被回收了,等于是自愈了 }
}
因为是 static ,就一直存在 到程序退出,但是我们也可以看到它有自愈功能,就是说如果你的 Stack 最多有 100 个对象,那么最多也就只有 100
个对象无法 被回收, 其实这个应该很容易理解,Stack 内部持有 100 个引用,最坏的情况就是 他们都是无用的,因为我们一旦放新的进取,以前的引用自然消失!

内存泄露的另外一种情况: 当一个对象被存储进 HashSet 集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的晗希值与
最初存储进 HashSet 集合中时的哈希值就不同了,在这种情况下,即使在 contains 方法使用该对象的当前引用作为的参数去 HashSet
集合中检索对象, 也将返回找不到对象的结果,这也会导致无法从 HashSet 集合中单独删除当前对象,造成内存泄露。

最后:

现在正是金三银四跳槽找工作面试季,最近有一些小伙伴粉丝让我帮忙找一些 面试题
资料。为帮助开发者们提升面试技能、有机会入职BATJ等大厂公司,于是我翻遍了收藏的 5T 资料后特别制作了这个专辑——这一次整体放出。

说明一下:所有的面试题目都不是一成不变的,特别是像一线大厂,下面的面试题只是给大家一个借鉴作用,最主要的是给自己增加知识的储备,有备无患。大致内容包括了:
Java
集合、JVM、多线程、并发编程、设计模式、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、spring面试题、spring
cloud面试题、spring boot面试题、spring教程 笔记、spring
boot教程笔记、最新阿里巴巴开发手册(63页PDF总结)、2022年Java面试手册一共整理了1184页PDF文档。

获取以上面试题集资料方式:私信(555)领取,祝大家更上一层楼!!

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信