我刚刚接受了一次采访,被要求用Java创建内存泄漏。
不用说,我觉得自己很傻,不知道如何开始创作。
什么样的例子?
我刚刚接受了一次采访,被要求用Java创建内存泄漏。
不用说,我觉得自己很傻,不知道如何开始创作。
什么样的例子?
当前回答
什么是内存泄漏:
这是由错误或不良设计引起的。这是在浪费记忆。随着时间的推移,情况会变得更糟。垃圾收集器无法清理它。
典型示例:
对象缓存是一个很好的起点,可以让事情变得一团糟。
private static final Map<String, Info> myCache = new HashMap<>();
public void getInfo(String key)
{
// uses cache
Info info = myCache.get(key);
if (info != null) return info;
// if it's not in cache, then fetch it from the database
info = Database.fetch(key);
if (info == null) return null;
// and store it in the cache
myCache.put(key, info);
return info;
}
您的缓存不断增长。很快整个数据库就被吸进了内存。更好的设计使用LRUMap(仅将最近使用的对象保存在缓存中)。
当然,你可以让事情变得更加复杂:
使用ThreadLocal构造。添加更复杂的参考树。或由第三方库引起的泄漏。
经常发生的情况:
如果此Info对象引用了其他对象,则这些对象也引用了其他的对象。在某种程度上,您也可以认为这是某种内存泄漏(由糟糕的设计导致)。
其他回答
每个人都会忘记本机代码路径。以下是泄漏的简单公式:
声明本机方法。在本机方法中,调用malloc。不要打免费电话。调用本机方法。
记住,本机代码中的内存分配来自JVM堆。
要做的一件简单的事情是使用带有不正确(或不存在)hashCode()或equals()的HashSet,然后继续添加“重复项”。而不是像应该的那样忽略重复项,集合只会增长,您将无法删除它们。
如果你想让这些坏键/元素到处乱动,你可以使用一个静态字段,比如
class BadKey {
// no hashCode or equals();
public final String key;
public BadKey(String key) { this.key = key; }
}
Map map = System.getProperties();
map.put(new BadKey("key"), "value"); // Memory leak even if your threads die.
关于如何在Java中创建内存泄漏,有很多答案,但请注意采访中提出的问题。
“如何使用Java创建内存泄漏?”是一个开放式问题,其目的是评估开发人员的经验程度。
如果我问你“你有解决Java内存泄漏的经验吗?”,你的答案很简单:“是”。然后,我会继续说“你能给我举个例子来解决内存泄漏问题吗?”,你会给我一两个例子。
然而,当面试官问“如何用Java创建内存泄漏?”时,预期答案应该是以下几行:
我遇到了内存泄漏。。。(说什么时候)[这显示了我的经验]导致它的代码是。。。(解释代码)[你自己修的]我应用的修复基于。。。(解释修复)[这让我有机会询问修复的细节]我做的测试是。。。[让我有机会询问其他测试方法]我是这样记录的。。。[额外加分。如果你记录下来,那就好了]因此,有理由认为,如果我们按照相反的顺序执行,也就是说,得到我修复的代码,然后删除我的修复,我们就会出现内存泄漏。
当开发人员未能遵循这一思路时,我试图引导他/她问“你能给我一个Java如何泄漏内存的例子吗?”,然后问“你曾经修复过Java中的内存泄漏吗?”
请注意,我并不是在询问如何在Java中泄漏内存的示例。那太傻了。谁会对一个能够有效编写泄漏内存的代码的开发人员感兴趣?
Java1.6中的String.substring方法会造成内存泄漏。这篇博文解释了这一点:
SubString方法在Java中的工作原理-JDK1.7中修复了内存泄漏
可能是潜在内存泄漏以及如何避免它的最简单示例之一,是ArrayList.remove(int)的实现:
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index + 1, elementData, index,
numMoved);
elementData[--size] = null; // (!) Let gc do its work
return oldValue;
}
如果您是自己实现的,您是否想过清除不再使用的数组元素(elementData[-size]=null)?该引用可能会使一个巨大的对象保持活力。。。