Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 休眠内存不足堆错误_Java_Hibernate - Fatal编程技术网

Java 休眠内存不足堆错误

Java 休眠内存不足堆错误,java,hibernate,Java,Hibernate,我有一个Java应用程序,除其他外,它每小时都会进入我们的Active Directory服务器,并提取所有帐户的列表,并将它们转储到数据库中;这项工作是通过每小时产生一个新线程来完成的,数据库接口是通过Hibernate完成的。线程的run方法(本质上是该线程唯一做的事情)如下所示: public void run() { try { Thread.sleep(3600000); //we run once an hour, so we sleep for an hou

我有一个Java应用程序,除其他外,它每小时都会进入我们的Active Directory服务器,并提取所有帐户的列表,并将它们转储到数据库中;这项工作是通过每小时产生一个新线程来完成的,数据库接口是通过Hibernate完成的。线程的run方法(本质上是该线程唯一做的事情)如下所示:

public void run() {
    try {
        Thread.sleep(3600000); //we run once an hour, so we sleep for an hour
        Thread newHourlyRunThread = new Thread(new HourlyRunThread());
        newHourlyRunThread.start();
        LDAPNewUsersReport report = new LDAPNewUsersReport();
        Calendar calendar = Calendar.getInstance();
        calendar.set(0, 0, 0, 0, 0); //We tell the report to look for everything from 12AM Jan 1 0 AD, which should be sufficient to find all created AD objects.
        report.runReport(calendar.getTime(), new Date());
        HashSet<LDAPEntry> allEntries = report.getAllEntries();
        Iterator it = allEntries.iterator();
        while (it.hasNext()) {
            ContactParser.parseContact((LDAPEntry) it.next());
        }
}
如果我们只运行一个实例(因此,之后不会产生新线程),这一切都会非常好地工作,但是如果我们多次运行此线程(即,我将执行速度提高到~30秒,以便可以看到问题),Hibernate会报告堆空间不足。这似乎不是一个特别密集的数据集(只有大约6K个条目),但当我们将代码转移到staging错误以准备推到生产时,我看到了相同的错误。我在编写有效线程方面没有经验,在Hibernate方面也没有经验,因此,如果有人知道什么可能会耗尽我们的堆空间(此应用程序中的另一个主要线程没有同时运行,并且占用了数百KB的内存总量),请查看代码,如有任何建议,我将不胜感激


提前感谢。

是一款免费的开源强大Java堆分析器。我已经多次使用它来确定内存泄漏的来源。使用此工具,您将能够快速查看hibernate是否是要惩罚的对象;-)

您可以使用重新编写,我怀疑部分问题在于您正在创建大量
HourlyRunThread
对象,而您只需要一个

例如,此测试演示了如何安排线程每秒运行10秒

@Test(expected = TimeoutException.class)
public void testScheduledExecutorService() throws InterruptedException, ExecutionException, TimeoutException {
    final AtomicInteger id = new AtomicInteger();
    final ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
    service.scheduleAtFixedRate(new Runnable() {
        public void run() {
            System.out.println("Thread" + id.incrementAndGet());
        }
    }, 1, 1, TimeUnit.SECONDS).get(10, TimeUnit.SECONDS);
}
这将提供运行时所期望的输出,因为此测试在10秒的运行时间内创建了近10k个线程

private static final class HourlyRunThread extends Thread {
    private static final AtomicInteger id = new AtomicInteger();
    private final int seconds;

    private HourlyRunThread(final int seconds) {
        super("Thread" + id.incrementAndGet());
        this.seconds = seconds;
    }

    public void run() {
        try {
            Thread.sleep(seconds);
            if (seconds < 10) {
                Thread newHourlyRunThread = new Thread(new HourlyRunThread(seconds));
                newHourlyRunThread.start();
            }
            // do stuff
            System.out.println(getName());
        } catch (InterruptedException e) {
        }
    }
}

@Test
public void testThreading() {
    final Thread t = new HourlyRunThread(1);
    t.start();
}
private静态最终类HourlyRunThread扩展线程{
私有静态最终AtomicInteger id=新的AtomicInteger();
私人最后整数秒;
私有HourlyRunThread(最后整数秒){
超级(“线程”+id.incrementAndGet());
这个。秒=秒;
}
公开募捐{
试一试{
睡眠(秒);
如果(秒<10){
线程newHourlyRunThread=新线程(新的HourlyRunThread(秒));
newHourlyRunThread.start();
}
//做事
System.out.println(getName());
}捕捉(中断异常e){
}
}
}
@试验
公共void testThreading(){
最终螺纹t=新的小时退螺纹(1);
t、 start();
}

看起来您正在进行批量插入或更新,在这种情况下,您应该定期刷新和清除Hibernate会话,以便会话级缓存不会占用超过分配的空间

请参阅Hibernate手册中关于的一章,以获取有关如何完成此任务的建议


此外,我强烈建议找到另一种方法在预定的时间范围内启动您的任务,或者使用Jon Freedman建议的ScheduledExecutorService,或者使用类似的库。在启动实际线程执行工作之前,让线程休眠3600000毫秒似乎是一种非常有问题(且不确定)的处理方法。

谢谢大家的建议,但事实证明,我们收到的错误实际上是由本地测试和登台之间的配置错误引起的——数据库是新的,权限配置不正确,无法允许登台区域与创建的数据库对话。当使用正确的权限运行时,它就像一个符咒


我肯定会考虑为Hibernate设置批处理设置,并转移到线程调度程序,而不是我当前的黑客系统。

我不小心为每个事务创建了一个新的
会话工厂。由于某种原因,
GC
无法清理那些旧的
sessionfactories


始终使用相同的
SessionFactory
实例解决了我的问题。

您尝试过分析应用程序吗?另外,查看
-Xmx
-Xms
命令行参数。有一些有用(免费)的Java内存评测软件包。@Dave Jarvis:正在尝试评测。至于增加堆大小:理想情况下,我希望尽量避免这种情况,因为这最终将运行在一个有许多其他进程的服务器上,我希望成为一个好公民,而不是为一个小应用程序需要大量内存。谢谢,我来试试。@jon freedman:谢谢你对线程启动的建议。我有一种感觉,这不是最好的方法,我会朝着比现在更好的方向努力。我也非常感谢有关Hibernate批处理的信息,我会看看这是否会有所不同。我还建议在单个事务中每小时运行一次“任务”的所有工作,而不是每次更新一个事务-这可能有助于总的执行时间,而且可能在语义上更为正确(也就是说,所有作业一次成功,或者没有一个成功)。不过,这取决于所需的隔离/原子性级别。
private static final class HourlyRunThread extends Thread {
    private static final AtomicInteger id = new AtomicInteger();
    private final int seconds;

    private HourlyRunThread(final int seconds) {
        super("Thread" + id.incrementAndGet());
        this.seconds = seconds;
    }

    public void run() {
        try {
            Thread.sleep(seconds);
            if (seconds < 10) {
                Thread newHourlyRunThread = new Thread(new HourlyRunThread(seconds));
                newHourlyRunThread.start();
            }
            // do stuff
            System.out.println(getName());
        } catch (InterruptedException e) {
        }
    }
}

@Test
public void testThreading() {
    final Thread t = new HourlyRunThread(1);
    t.start();
}