内存泄漏:指的是应用程序中存在无用的对象或者资源没有被垃圾回收机制回收,从而导致内存占用不断增加,最终导致应用程序的崩溃。
jvm里对象的引用按照从强到弱,分为四个强,软,弱,虚。强引用不会被GC回收,剩下三个都可能会被回收。
如
ThreadLocal<Long> threadLocal = new ThreadLocal<>();
本身threadLocal 不存储值,当我们
threadLocal.set(value);
实际上是对线程独有的ThreadLocalMap进行ThreadLocalMap.set(threadLocal.hashcode(),value)
很明显是把threadLocal 当作key来用。
泄漏原因:弱引用threadLocal 可能会被GC回收,造成ThreadLocalMap中变成了(Null,value) 而这部分的内存没有被释放就会造成内存泄漏了。
当然有的人会说,当我们线程结束ThreadLocalMap不就会被释放了吗?这样不就会没有内存泄漏了吗。确实如此对于tomcat老版本它采用的是BIO模型,一个线程一个请求,不会存在threadLocal 内存泄漏问题。
但是对于其它的web服务器和高版本的tomcat其实内部用到的是NIO,基于线程池的思想,线程可能会被复用,而不是销毁。这样就会造成ThreadLocalMap内存一直不被释放,这就造成内存泄漏问题。
如何解决threadlocal内存泄漏呢?
每次使用完 ThreadLocal 以后,主动调用 remove()方法移除数据,释放内存
而static final 修饰threadlocal有些人说能够解决内存泄漏,修饰之后threadlocal对象不会被回收,可key为null的线程就不会发生,后续就可以复用这个threadlocal。而我认为这并没有解决内存泄漏中,因为这样并没有释放内存。虽然可以复用,但是对于后续不再使用threadlocal达不到解决的要求
科普 io模型
BIO(Blocking I/O):传统的 Servlet 容器(如 Tomcat 7 及以前版本)通常使用 BIO。BIO 是一种阻塞式 I/O 模型,每个连接都需要独立的线程进行处理,即一个线程对应一个连接。当一个线程处理一个请求时,其他连接将被阻塞。这种模型适用于低并发且连接数较少的情况。
NIO(Non-blocking I/O):随着 Java NIO 应用程序编程接口的引入,许多 Web 服务器开始使用 NIO。NIO 提供了非阻塞的 I/O 操作,通过使用 Selector、Channel 和 Buffer 等关键概念,基于线程池,可以使用少量线程处理大量连接。NIO 允许在一个线程中处理多个连接,提高了服务器的并发处理能力。
AIO(Asynchronous I/O):AIO 是在 Java 7 中引入的,并且在 NIO 的基础上进一步扩展了非阻塞 I/O 的功能。AIO 使用异步操作处理 I/O 事件,当一个操作完成时,将触发回调通知应用程序。AIO 对于处理高并发且有大量I/O操作的场景更加有效,例如处理海量请求或大文件传输等。