我有一个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());
}
}
从ContactParser相关的方法如下:
public static void parseContact(LDAPEntry entry) {
Contact chosenContact = null;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
List contacts = session.getNamedQuery("ContactByCanonicalName").setString(0, entry.getDN()).list();
Iterator it = contacts.iterator();
if (it.hasNext()) {
chosenContact = (Contact) it.next();
chosenContact = ContactParser.fillContactFields(chosenContact, entry);
} else {
chosenContact = ContactParser.fillContactFields(new Contact(), entry);
}
session.saveOrUpdate(chosenContact);
session.getTransaction().commit();
}
private static Contact fillContactFields(Contact chosenContact, LDAPEntry entry) {
chosenContact.setCanonicalName(entry.getDN());
chosenContact.setFirstName(ContactParser.getEntryField(entry, "givenName"));
chosenContact.setLastName(ContactParser.getEntryField(entry, "sn"));
chosenContact.setUserName(ContactParser.getEntryField(entry, "sAMAccountname"));
chosenContact.setEmployeeID(ContactParser.getEntryField(entry, "employeeID"));
chosenContact.setMiddleName(ContactParser.getEntryField(entry, "initials"));
chosenContact.setEmail(ContactParser.getEntryField(entry, "mail"));
if(chosenContact.getFirstSeen() == null){
chosenContact.setFirstSeen(new Date());
}
chosenContact.setLastSeen(new Date());
return chosenContact;
}
private static String getEntryField(LDAPEntry entry, String fieldName){
String returnString = "";
if(entry.getAttribute(fieldName) != null){
returnString = entry.getAttribute(fieldName).getStringValue();
}
return returnString;
}
这所有的作品非常漂亮,如果我们只运行一个单一的实例(所以,没有新的线程是事后产生的),但如果我们不止一次运行这个线程(IE,我加快执行到~30秒,以便我可以看到问题),Hibernate报告缺乏堆空间。这看起来不像是一组特别强烈的数据(只有大约6K条目),但是当我们将代码碰到分级错误以准备推进生产时,我看到了同样的错误。在编写高效的线程方面我缺乏经验,而在Hibernate方面缺乏经验,所以如果有人有一个想法,可能会耗尽我们的堆空间(这个应用程序中的另一个主要线程没有同时运行,并且占用了几百千字节的内存),我非常感谢任何建议。
在此先感谢。
您是否尝试过分析该应用程序?另外,请查看'-Xmx'和'-Xms'命令行参数。有一些有用的(和免费的)用于Java的内存分析软件包。 – 2010-10-05 15:00:07
@Dave Jarvis:现在尝试进行配置。至于增加堆大小:理想情况下,我想尽量避免这种情况,因为这最终将在具有许多其他进程的服务器上运行,并且我想成为一个好公民,而不是需要巨大的这是一个小小的应用程序的记忆堆。 – EricBoersma 2010-10-05 15:05:26