这篇文章主要讲解了“Java中导致内存泄漏原因是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java中导致内存泄漏原因是什么”吧!
内存泄漏指的是在应用程序运行周期中内存占用持续性增长。然而Java的内存泄漏更准确地描述为: 排除外部压力干扰情况下,在JVM一个全垃圾回收(Full GC)周期内,内存未能恢复到初始化内存大小并且在多个全垃圾回收之后内存仍持续性增长,视为内存泄漏。
Jvm引入垃圾回收机制,当初垃圾回收机制设计的目的是为了解决C、C++编程语言上的需要手动释放内存的缺陷(准确地来说这并不算缺陷,只能说是手动释放比较麻烦)。总结GC的运行过程,当vm栈对vm堆中的引用失效之后,GC就会将vm堆中的此对象纳入回收范围,只要堆对象引用一直存在着,GC就不会进行回收。因此当对象使用完毕之后并未打断引用,就会导致内存泄漏。然而引用为何未被打断,请看下文《三、 导致内存泄漏原因》
内存泄漏的根本原因是引用未被打断。根据我个人经验,总结引用未被打断的原因有以下几种,如有错漏,敬请谅解
句柄,是引用windows操作系统的概念,Linux上称为文件描述符,对Linux来说Everything Is File(所有东西都是文件)。此处设计到句柄的操作类有 InputSteam,OuputStream,Socket,Connection...等及其子类或者实现类。个人认为,Java中所有实现了Closable接口的类都会属于句柄类。所有句柄类在使用过后必须要进行关闭,否则将导致句柄泄漏从而引起内存泄漏。
Closabe接口代码:
Closable接口实现类:
举个例子: InputStream/FileInputStream
无内存泄漏运行代码结果:句柄数200
有内存泄漏运行代码结果:句柄数201
原因在于 InputStream实现了Closable接口,在使用时未关闭。因此会一直占用此句柄,导致内存泄漏。
另外有人问线程是否属于句柄,我在这里告诉你,线程不算句柄,但是启动一个线程将会引入大约7个句柄。请看3.2线程测试结果。
3.2.1、线程,在Java中有独立的线程实现,实现线程有2种方式,第一种是实现runable接口,第二种是继承Thread类。当且仅当JVM中正在运行的线程数>0时,JVM会持续运行。
3.2.2、线程停止有3种方式
3.2.2.1、线程自然结束,让线程完成工作之后自然结束(自然老死)
3.2.2.2、调用线程interrupt方法,另外一个线程去调用正在运行的线程interrupt方法(被杀)
3.2.2.3、调用线程stop方法,另外一个线程去调用正在运行的线程stop方法(被杀,此方法已过期)
显而易见,使用线程自然结束的方式最为和谐。自然结束代码如下:
另线程持续运行代码:
线程未释放内存泄漏代码:
无内存泄漏运行代码结果:运行之后所有线程结束,JVM也关闭了。
有内存泄漏运行代码结果:线程不断创建,已创建的线程持续运行,内存不会释放
JVM默认启动使用17个线程,200个句柄,本例中启动了1000个线程,线程数增加到1017个,句柄数增加到7202个,大约每创建一个句柄将会占用7个句柄,消耗1M内存。
Java中引入异常处理概念,可以捕捉各种各样的异常。适当使用异常将有助于提高系统稳定性能。
在3.1描述中,使用了代码Try...catch...finally 此块代码的目的是保证能够调用到close方法,避免内存泄漏。
按照良好的编程习惯,当一块代码未知运行结果和可能有未知异常时,建议使用 Try...catch...finally语句,避免程序抛出未知异常导致部分资源未被释放。
继续以3.1为例:
无内存泄漏运行代码结果:句柄数200
有内存泄漏运行代码结果:句柄数201
集合作为JVM内部的快速存储方案,使用起来确实方便,然而在定义存储时使用不当也将导致内存泄漏,原因就是引用一直存在着。
结果是显而易见的!!!
感谢各位的阅读,以上就是“Java中导致内存泄漏原因是什么”的内容了,经过本文的学习后,相信大家对Java中导致内存泄漏原因是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。