面试官:小伙子,你给我说一下Java中什么情况会导致内存泄漏呢?
概念
内存泄露:指程序中动态分配内存给一些临时对象,但对象不会被GC回收,它始终占用内存,被分配的对象可达但已无用。即无用对象持续占有内存或无用对象的内存得不到及时释放,从而造成的内存空间浪费。
可达性分析算法
JVM使用可达性分析算法判断对象是否存活。
GC Root
通过一系列名为“GC Roots”的对象作为起点,从这些结点开始向下搜索,搜索所走过的路径称为“引用链(Reference Chain)”,当一个对象到GC Roots没有任何饮用链相连时,则证明此对象是不可用的。
object4、object5、object6虽然有互相判断,但是它们到GC Rootd是不可达的,所以它们将会判定为是可回收对象。
可以作为GC Roots的对象有:
- 虚拟机栈(栈帧中的本地变量表)中的引用的对象;
- 方法区中的类静态属性引用的对象;
- 方法区中的常量引用的对象;
- 本地方法栈中JNI的引用的对象
虽然Java有垃圾收集器帮组实现内存自动管理,虽然GC有效的处理了大部分内存,但是并不能完全保证内存的不泄漏。
内存泄漏
内存泄漏就是堆内存中不再使用的对象无法被垃圾收集器清除掉,因此它们会不必要地存在。这样就导致了内存消耗,降低了系统的性能,最终导致OOM使得进程终止。
内存泄漏的表现:
- 应用程序长时间连续运行时性能严重下降;
- 应用程序中的OutOfMemoryError堆错误;
- 自发且奇怪的应用程序崩溃;
- 应用程序偶尔会耗尽连接对象;
可能导致内存泄漏的原因:
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()方法。
6. 常量字符串造成的内存泄漏
如果我们读取一个很大的String对象,并调用了intern(),那么它将放到字符串池中,位于PermGen中,只要应用程序运行,该字符串就会保留,这就会占用内存,可能造成OOM。(针对JDK1.6及以前,常量池在PermGen永久代中)
解决办法:增加PermGen的大小,-XX:MaxPermSize=512M;JDK1.7以后字符串池转移到了堆中。
intern()方法详解:
String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
String str4 = str3.intern();
System.out.println(str1 == str2);
System.out.println(str2 == str3);
System.out.println(str1 == str4);
System.out.println(str3 == str4);
true, false, true, false
intern()方法搜索字符串常量池,如果存在指定的字符串,就返回之;
否则,就将该字符串放入常量池并返回之。
换言之,intern()方法保证每次返回的都是 同一个字符串对象
String str1 = "abc";
String str2 = "abc";
String str3 = new String("abcd");
String str4 = str3.intern();
String str5 = "abcd";
System.out.println(str1 == str2);
System.out.println(str2 == str3);
System.out.println(str1 == str4);
System.out.println(str3 == str4);
System.out.println(str4 == str5);
true
false
false
false
true
为何要使用intern()方法?看看equals方法的源码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
可以看到,比较两个字符串的时候,首先比较两个字符串对象是否地址相同,不同再挨个比较字符。这样就大大加快了比较的速度。否则若每次都挨个比较将是非常耗时的。
7. 使用ThreadLocal造成内存泄漏
使用ThreadLocal时,每个线程只要处于存活状态就可保留对其ThreadLocal变量副本的隐式调用,且将保留其自己的副本。使用不当,就会引起内存泄漏。
一旦线程不再存在,该线程的threadLocal对象就应该被垃圾收集,而现在线程的创建都是使用线程池,线程池有线程重用的功能,因此线程就不会被垃圾回收器回收。所以使用到ThreadLocal来保留线程池中的线程的变量副本时,ThreadLocal没有显式地删除时,就会一直保留在内存中,不会被垃圾回收。
解决办法:不再使用ThreadLocal时,调用remove()方法,该方法删除了此变量的当前线程值。不要使用ThreadLocal.set(null),它只是查找与当前线程关联的Map并将键值中这个threadLocal对象所对应的值为null,并没有清除这个键值对。
最后
大家看完有什么不懂的可以在下方留言讨论,也可以关注我私信问我,我看到后都会回答的。也欢迎大家关注我的公众号:前程有光,马上金九银十跳槽面试季,整理了1000多道将近500多页pdf文档的Java面试题资料放在里面,助你圆梦BAT!文章都会在里面更新,整理的资料也会放在里面。谢谢你的观看,觉得文章对你有帮助的话记得关注我点个赞支持一下!
面试官:小伙子,你给我说一下Java中什么情况会导致内存泄漏呢?的更多相关文章
- 一线大厂面试官最喜欢问的15道Java多线程面试题
前言 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分.如果你想获得更多职位,那么你应该准备很多关于多线程的问题. 他们会问面试者很多令人混淆的Java线程问题.面试官只是想确信面试者 ...
- 【Spring注解驱动开发】面试官:如何将Service注入到Servlet中?朋友又栽了!!
写在前面 最近,一位读者出去面试前准备了很久,信心满满的去面试.没想到面试官的一个问题把他难住了.面试官的问题是这样的:如何使用Spring将Service注入到Servlet中呢?这位读者平时也是很 ...
- 面试官:如何在Integer类型的ArrayList中同时添加String、Character、Boolean等类型的数据? | Java反射高级应用
原文链接:原文来自公众号:C you again,欢迎关注! 1.问题描述 "如何在Integer类型的ArrayList中同时添加String.Character.Boolean等 ...
- 搞定面试官:咱们从头到尾再说一次 Java 垃圾回收
接着前几天的两篇文章,继续解析JVM面试问题,送给年后想要跳槽的小伙伴 万万没想到,面试中,连 ClassLoader类加载器 也能问出这么多问题..... 万万没想到,JVM内存区域的面试题也可以问 ...
- 面试官:我们来聊一聊Redis吧,你了解多少就答多少
哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新,建议收藏关注 一.前言 作为一名Java程 ...
- 面试官:说一说Zookeeper中Leader选举机制
哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 今天又是一个阳光明媚的一天,我又 ...
- 如何写出面试官欣赏的Java单例
单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例. 今天我们不谈单例模式的用途,只说一说如果在面试的时候面试官让你敲一段代码 ...
- 【JAVA秒会技术之秒杀面试官】秒杀Java面试官——集合篇(一)
[JAVA秒会技术之秒杀面试官]秒杀Java面试官——集合篇(一) [JAVA秒会技术之秒杀面试官]JavaEE常见面试题(三) http://blog.csdn.net/qq296398300/ar ...
- Java面试官最爱问的volatile关键字
在Java的面试当中,面试官最爱问的就是volatile关键字相关的问题.经过多次面试之后,你是否思考过,为什么他们那么爱问volatile关键字相关的问题?而对于你,如果作为面试官,是否也会考虑采用 ...
随机推荐
- ssh免密登陆 2
应用场景之一:java 程序调用shell脚本,通过ssh 免密登陆数据库服务器,进行数据的抽取打包工作. 免密设置步骤: 1.客户端生成公私钥,在任意目录下执行命令ssh-keygen(一路回车默认 ...
- altium designer使用小技巧,记录
1.在自建库文件中添加component File--open----schlib或pcblib---Tools---new component---绘制---保存. 2.编辑component 左边 ...
- makefile管理项目
makefile: 管理项目. 命名:makefile Makefile --- make 命令 1 个规则: 目标:依赖条件 (一个tab缩进)命令 1. 目标的时间必须晚于依赖条件的时间,否则,更 ...
- MongoDB用户,角色管理 --- MongoDB基础用法(三)
用户管理 用户创建 MongoDB采用基于角色的访问控制(RBAC)来确定用户的访问. 授予用户一个或多个角色,确定用户对MongoDB资源的访问权限和用户可以执行哪些操作. 用户应该只有最小权限集才 ...
- K近邻算法:机器学习萌新必学算法
摘要:K近邻(k-NearestNeighbor,K-NN)算法是一个有监督的机器学习算法,也被称为K-NN算法,由Cover和Hart于1968年提出,可以用于解决分类问题和回归问题. 1. 为什么 ...
- 专题五:redis的数据类型之set
一.基本简介 现在出现了新的查询需求:存储大量数据的同时,还需要在查询方面提供更高的效率.虽然list满足存储大量的数据,也可以通过索引来进行访问,但是list底层是双向链表的结构,在查询上的效率并没 ...
- linux添加自动清空缓存
1. cleanCache.sh vim cleanCache.sh #!/bin/bash #每两小时清除一次缓存 echo "开始清除缓存" sync;sync;sync #写 ...
- VSCcode中使用git
1.配置 文件 -> 首选项 -> 配置 出现json格式的配置项,左侧为默认设置,右侧为自定义设置: 加一行: "git.path": Git目录下cmd下的git ...
- git clone下载速度慢的解决方案
由于自己碰到git clone速度慢的问题,查询后发现有一个很好用的方法 首先获得你git clone的原格式,例如: git clone https://github.com/graykode/nl ...
- python编写实现抽奖器
这篇文章主要为大家详细介绍了python编写实现抽奖器,文中代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 # coding=utf-8 import sys import os ...