hibernate中List出现Java heap space的解决方案
2020-03-19 09:19:12
lzh


近期发现在Lerx的一些客户中出现 java.lang.OutOfMemoryError: Java heap space 错误。

经过测试,在少量的一些栏目页中会出现这种情况。查询资料,是内存不足的原因。分析原因,一些用户在发表文章时采用word粘贴的方式,文章正文中含有大量的Word垃圾代码,这使得文章正文的长度超长,当采用List<Article>取这结果集时,这个List可能超过了内存限制。原因是Lerx的许多客户采用的是虚拟主机,这些主机用户被空间商限制了JVM的内存,比如只有64MB。测试时,独立主机均没有这种现象发生。

两种方法可以解决这种问题。

一个将HQL的“from OBJ” 语句格式改为“select new OBJ(o.a,o.b,o.c ...)”方式,在提取时仅提取需要的字段。这种方式就需要在OBJ对象中添加构造函数。

如:

public class OBJ {

	private Long id;
	private String a;
	private String b;
	private String c;
	...
	
	public OBJ{}

	public OBJ(Long id,String a,String b,String c){
		this.id=id;
		this.a=a;
		this.b=b;
		this.c=c;
		...
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getA() {
		return a;
	}

	public void setA(String a) {
		this.a = a;
	}

	.....

}

这种方式常常会发生问题,比如:select new OBJ(...)方括号内的参数与构造函数中的顺序或类型不一致。再者,当出现Timestamp类型是会很难处理,系统会直接报错,网上有一个转换的方法,但经测试该方法在本例中无效。

综合上述,在Lerx中,采用了另一种方法,改变一下hibernate的传统使用方法。

原先,我们在用hibernate时,提取时直接提取了对象的List,现在改一下,改为仅提取对象的id,这将会只占用极小的内存空间。

要用到对象时,再打一下就行了。

如:

final String hql = "select a.id from ArticleThread a " + hqlTmp + orderStr;
		HibernateCallback hc = new HibernateCallback() {

			@SuppressWarnings("unchecked")
			@Override
			public Object doInHibernate(org.hibernate.Session session)
					throws HibernateException, SQLException {
				int n = pageSize;
				if (n == 0) {
					n = 10;
				}
				Query query = session.createQuery(hql);
				query.setFirstResult((page - 1) * pageSize);
				query.setMaxResults(n);

				List<Long> list = query.list();

				if (list.isEmpty()) {
					// System.out.println("找不到记录");
				}
				// System.out.println("测试点5");
				return list;
			}

		};
发布:lzh