You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate/Spring应用StatefulPersistenceContext内存占用过高排查

基于Hibernate+Spring应用的内存溢出问题排查求助

我有一个基于Hibernate和Spring的应用,处理中等规模数据集(约300万条记录)时出现内存不足问题。用Eclipse Memory Analyser分析内存转储后发现,StatefulPersistenceContext除了持有对象本身,还在内存中保存了一份记录副本,直接导致内存使用量翻倍。

我能通过以下小规模工作流复现问题:

  • 从文件向数据库插入约40万条Fruit记录
  • 从数据库获取所有Fruit,查找互补项创建约15万条包含两个Fruit的Basket记录
  • 检索所有Fruit和Basket数据并保存到文件

问题出在最后一步,堆转储显示StatefulPersistenceContext在内存中保存了数十万条Fruit,和为保存文件检索的Fruit重复。

我已经尝试过以下方案,但都没解决StatefulPersistenceContext内存占用过高的问题:

  • 在查询中添加QueryHints.READ_ONLY(加在getAll方法上)
  • 在带readOnly属性的Transaction中执行查询

请问还有哪些需要排查的点?


相关类/查询示例

ShoppingService 接口

public interface ShoppingService {
    public void createBaskets();

    public void loadFromFile(ObjectInput input);

    public void saveToFile(ObjectOutput output);
}

ShoppingServiceImpl 实现类

@Service
public class ShoppingServiceImpl implements ShoppingService {
    @Autowired
    private FruitDAO fDAO;

    @Autowired
    private BasketDAO bDAO;

    @Override
    public void createBaskets() {
        bDAO.add(Basket.generate(fDAO.getAll()));
    }

    @Override
    public void loadFromFile(ObjectInput input) {
        SavedState state = ((SavedState) input.readObject());

        fDAO.add(state.getFruits());
        bDAO.add(state.getBaskets());
    }

    @Override
    public void saveToFile(ObjectOutput output) {
        output.writeObject(new SavedState(fDAO.getAll(), bDAO.getAll()));
    }

    public static void main(String[] args) throws Throwable {
        ShoppingService service = null;

        try (ObjectInput input = new ObjectInputStream(new FileInputStream("path\\to\\input\\file"))) {
            service.loadFromFile(input);
        }

        service.createBaskets();

        try (ObjectOutput output = new ObjectOutputStream(new FileOutputStream("path\\to\\output\\file"))) {
            service.saveToFile(output);
        }
    }
}

Fruit 实体类

@Entity
public class Fruit {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    private String name;

    // ~ 200 string fields
}

FruitDAO 接口

public interface FruitDAO {
    public void add(Collection<Fruit> elements);

    public List<Fruit> getAll();
}

JPAFruitDAO 实现类

@Repository
public class JPAFruitDAO implements FruitDAO {
    @PersistenceContext
    private EntityManager em;

    @Override
    @Transactional()
    public void add(Collection<Fruit> elements) {
    elements.forEach(em::persist);
    }

    @Override
    public List<Fruit> getAll() {
    return em.createQuery("FROM Fruit", Fruit.class).getResultList();
    }
}

Basket 实体类

@Entity
public class Basket {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    @OneToOne
    @JoinColumn(name = "arow")
    private Fruit aRow;

    @OneToOne
    @JoinColumn(name = "brow")
    private Fruit bRow;

    public static Collection<Basket> generate(List<Fruit> fruits) {
    // Some complicated business logic that does things
    return null;
    }
}

BasketDAO 接口

public interface BasketDAO {
    public void add(Collection<Basket> elements);

    public List<Basket> getAll();
}

JPABasketDAO 实现类

@Repository
public class JPABasketDAO implements BasketDAO {
    @PersistenceContext
    private EntityManager em;

    @Override
    @Transactional()
    public void add(Collection<Basket> elements) {
    elements.forEach(em::persist);
    }

    @Override
    public List<Basket> getAll() {
    return em.createQuery("FROM Basket", Basket.class).getResultList();
    }
}

SavedState 类

public class SavedState {
    private Collection<Fruit> fruits;
    private Collection<Basket> baskets;
}

内容的提问来源于stack exchange,提问作者JackPGreen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 01:50:34