我注意到我的java项目消耗了大量内存。在使用Visualvm.exe进行简短调查后,我发现了消耗大部分内存的线程,这些是计时器线程。 我在我的项目中使用了三种计时器:
在visualvm中检查时,所有这些线程随着时间的推移在内存消耗中增长,我投入的代码/对象越多,它们在内存中的增长就越快。但是,在一些阈值(我的机器上每个线程大约50-100 MB)之后,应用程序在内存大小上停止增长。
如果我使用了一个或两个计时器,这不会成为一个问题,但我需要使用很多,这个50-100 MB的阈值会随着时间的推移产生非常显着的内存消耗。
有人可以就这件事分享经验吗?
我还尝试用递归线程替换计时器,虽然这种方法很不常见,但它有点奏效。
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Main {
private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
private Timer utilTimer = new Timer();
private javax.swing.Timer swingTimer;
public static void main(String[] args) throws InterruptedException {
new Main();
}
private Main() {
executor.scheduleAtFixedRate(new Runnable() {
public void run() {
Thread.currentThread().setName("executor");
}
}, 0, 500, TimeUnit.MILLISECONDS);
utilTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Thread.currentThread().setName("utilTimer");
}
}, 0, 500);
swingTimer = new javax.swing.Timer(500, new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
Thread.currentThread().setName("swingTimer");
}
});
swingTimer.setRepeats(true);
swingTimer.start();
recursiveThread();
}
private void recursiveThread() {
Thread thread = new Thread() {
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
recursiveThread();
}
};
thread.setName("recursiveThread");
thread.start();
}
}
答案 0 :(得分:0)
每个线程50到100MB听起来非常错误。默认的Java线程堆栈大小为1MB。如果你得到这个大小的内存开销,还有其他事情可以导致它。 (您是否通过java
命令行选项更改默认堆栈大小?)
另一个观察是,改变应用程序的体系结构以避免使用大量计时器是个好主意。定时器本质上很昂贵。
但是如果"很多计时器"是不可避免的,也许你应该研究哈希定时器: