我在某处读到,使用下面的类实例不是一个好主意,因为它可能会导致内存泄漏。有人可以告诉我这是否是有效的陈述吗?或者以这种方式使用它们有什么问题吗?
Map<Class<?>,String> classToInstance = new HashMap();
classToInstance.put(String.class,"Test obj");
原文由 Aravind Yarram 发布,翻译遵循 CC BY-SA 4.0 许可协议
我在某处读到,使用下面的类实例不是一个好主意,因为它可能会导致内存泄漏。有人可以告诉我这是否是有效的陈述吗?或者以这种方式使用它们有什么问题吗?
Map<Class<?>,String> classToInstance = new HashMap();
classToInstance.put(String.class,"Test obj");
原文由 Aravind Yarram 发布,翻译遵循 CC BY-SA 4.0 许可协议
正如 Stephen C 提到的,内存泄漏确实是因为类加载器。但问题比乍一看更严重。考虑一下:
mapkey --> class --> classloader --> all other classes defined by this classloader.
此外,
class --> any static members, including static Maps e.g. caches.
每当循环 web 应用程序或其他一些动态(类加载)加载的应用程序时,一些这样的静态缓存就会开始累积大量内存丢失。
有几种方法可以解决此问题。如果您不关心来自不同类加载器的同一类的不同“版本”,那么只需根据 Class.getName()
进行键,即 java.lang.String
。
另一种选择是使用 java.util.WeakHashMap
。这种形式的 Map 只维护对键的弱引用。弱引用不会阻塞 GC,因此它们的键值不会导致内存堆积。但是,这些值 没有 被弱引用。因此,如果值是例如用作键的类的实例,则 WeakHashMap
不起作用。
原文由 Dilum Ranatunga 发布,翻译遵循 CC BY-SA 2.5 许可协议
4 回答1.3k 阅读✓ 已解决
4 回答1.2k 阅读✓ 已解决
1 回答2.6k 阅读✓ 已解决
2 回答721 阅读✓ 已解决
2 回答1.7k 阅读
2 回答1.7k 阅读
2 回答1.3k 阅读
是的,你确实需要小心!例如,如果您的代码在 Web 容器中运行,并且您习惯于热部署 Web 应用程序,则对单个类对象的保留引用可能会导致严重的 permgen 内存泄漏。
这篇文章 详细解释了这个问题。但简而言之,问题在于每个类都包含对其类加载器的引用,而每个类加载器都包含对其加载的每个类的引用。因此,如果一个班级是可达的,那么所有班级都是。
另一件需要注意的事情是,如果您用作键的其中一个类被重新加载,那么:
请注意,您仍然会有内存泄漏。 HashMap 中使用的任何动态加载的类(键或值)和(至少)其他动态加载的类都将保持可访问。这意味着 GC 将无法卸载/删除它们。
以前的 permgen 泄漏现在是普通的堆和元空间存储泄漏。 (元空间是保存类的类描述符和代码对象的地方。)