在以下代码中: -
Set<Object> allObjects = new HashSet<>(1000);
while(...){ //really big loop - millions
Object s = getSomeObject();//returns a big object
allObjects.add(s);
if(allObject.size() == 1000){
//If allObjects has got big enough, process and proceed further
final Set<Object> allObjects_temp = new HashSet<>(allObjects); //--->a
allObject.clear();
//Process these objects in a separate tasks parallely
executerService.submit(new Runnable() {
public void run() {
processData(partner, allObjects_temp);//---->b
}
}));
}
}
Line-a 会创建一个新的集合,其中包含复制的元素。
在 line-b 中,这些元素正在另一个线程中处理。但是,匿名类正在通过Object s
访问外部类(allObjects_temp
)中的引用,我相信即使在任务完成之后,Java GC也无法收集在循环中创建的对象。
Java GC实际上是否会收集对象?如果愿意,请简要说明原因。如果它无法收集对象,我们如何解决这个问题呢?
参考:When exactly is it leak safe to use (anonymous) inner classes?
更新: 编写以下代码以验证内存泄漏。如果没有内存,代码应该永远运行。
public class MemoryLeak {
public static void main(String[] args) {
ExecutorService executerService = new ThreadPoolExecutor(10, 10, 50, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(50, true), new ThreadPoolExecutor.CallerRunsPolicy());
Set<Object> allObjects = new HashSet<>(1500);
for (int i = 0; i < 100000;) { // really big loop - millions
Object s = getSomeObject();// returns a big object
allObjects.add(s);
if (allObjects.size() == 1500) {
// If allObjects has got big enough, process and proceed further
final Set<Object> allObjects_temp = new HashSet<>(allObjects); // --->a
allObjects.clear();
// Process these objects in a separate tasks parallely
executerService.submit(new Runnable() {
public void run() {
processData(allObjects_temp);// ---->b
}
});
}
}
executerService.shutdown();
}
private static Object getSomeObject() {
return "hello" + (Math.random() * 100000) + "" + (Math.random() * 100000);
}
protected static void processData(Set<Object> allObjects_temp) {
try {
Runtime rt = Runtime.getRuntime();
System.err.println(String.format("Free: %d Mb, Total: %d Mb, Max: %d Mb", rt.freeMemory() / 1000000,
rt.totalMemory() / 1000000, rt.maxMemory() / 1000000));
Thread.sleep(10);
System.out.println("done");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结果: 代码永远在运行。我还检查了内存是否经常被释放,Jmap向我展示了Object s确实被垃圾收集了。我还是不完全明白怎么做?
答案 0 :(得分:1)
我认为上面的代码不会产生内存泄漏。
在热点JVM中,GC将通过可达性分析检查对象是否有效。而静态变量stack变量可以视为imageView = (ImageView)findViewById(R.id.imageView);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Do something here
loadImageFromUrl(url);
}
});
root。
在您的代码中,对象GC
变量的引用将存储在JVM堆栈中。将新对象引用分配给allObjects_temp
时,JVM堆栈没有保留旧对象allObjects_temp
的引用,然后当任务线程运行结束时,这意味着任务线程没有&#39} ; t保持旧对象的引用。因此,旧对象无法访问,GC可以收集它。
请参阅以下代码:
allObjects_temp
第1行的字节代码是:
Set<String> set=new HashSet<>();
while (true){
String s=new String("test");
set.add(s);
if(set.size()==100){
final Set<String> temp=new HashSet<>(set); //line 1
set.clear();;
}
}
line2表示最终变量存储在jvm堆栈中。