元空间满了(或溢出),可能是什么原因?

典型回答 Metaspace(元空间)是Java 8 引入的,用来替代了 PermGen(永久代)的,他主要用来存储:类的元信息(类的结构、方法签名、注解、常量池等),他和 PermGen 最大的区别是:Metaspace 是存在堆外内存的,而永久代是在堆上的。 虽然元空间不在堆上,但是如果元空间满了,是会发生FullGC的(虽然大多数情况下都没用)。 如果元空间满了,或者发生了溢出,或者是频繁的FullGC,那么可以考虑以下几种情况: 1、类加载的太多了(最常见!) 类加载并不只是说你项目中的你写的Class太多了,这些往往都不是类加载太多的主要原因,而是需要考虑哪些频繁动态生成类,比如:动态代理、CGLIB、JSP编译、Groovy脚本等等,他们都会在运行期动态生成类。 比如下面这个问题,就是一个元空间溢出的问题,具体原因就是类加载的太多了: ✅频繁FullGC问题排查 2、类加载器泄漏 类加载泄露,估计很多人不知道啥意思,其实就是同一个类名,被多个类加载器加载,因为会被认为是不同类,所以每个类加载器持有它加载的类,只要类加载器没有被 GC,类元信息就不能释放。就会持续占用你空间、。 比较常见的就是在热部署的情况下,比如Tomcat/IDEA热重启时类加载器没释放。 3、元空间太小 一般来说元空间用的都是堆外内存,默认都是可以自动扩容的,容量也都很大,但是如果有的时候你用MaxMetaspaceSize指定了大小,那么也会容易被干满。

March 22, 2026 · 1 min · santu

G1如何精确控制 STW的时间的?

典型回答 ✅ZGC和CMS和G1的区别对比? 上文中说过,G1的STW时长是可预测的,或者说,G1可以根据用户设定的目标停顿时间来动态调整垃圾回收行为。 通过-XX:MaxGCPauseMillis=<N>可以设置我们允许的G1的目标最大停顿时间(毫秒) 那么,G1是如何保证一次垃圾回收能够在这个时间范围内的呢? 主要是因为G1中的一个另外的关键方案,那就是** G1 会把堆(Heap)划分成多个等大小的 Region**。每个Region可以是Eden、Survivor、Old或Humongous(大对象区)区域中的任何一个。 有了这些分区之后,G1采用增量式的收集方式。它并不是在每次收集时处理整个堆,而是每次只选择一部分区域进行收集。G1会根据停顿时间目标,预测在给定的时间内可以处理多少区域。它通过记录每个区域的回收时间(包括复制对象的时间)来建立停顿预测模型(回收收益预测模型): G1通过维护一个区域回收的代价(时间)和收益(释放空间)的模型,来预测每次收集的停顿时间。它会选择一组区域,使得预计的停顿时间不超过设定的目标。这个模型会随着运行的进行而不断调整,以更准确地预测。 假设你设定 MaxGCPauseMillis=100;G1 会估算每个 Region 回收的“收益/成本比”;然后动态决定:这次 GC 要处理多少个 Region;让整个停顿时间 ≈ 100ms(即接近目标)。 就像大家评估工作量一样,一个大项目你评估下来肯定不准,不知道需要几天才能完成,但是如果你把其中的所有功能点都拆开,那么你就能很好地预估出写个Mapper、写一个方法、写个Dao所需的时间了。这时候如果只给你固定的时间,你就大概知道,可以砍哪些功能点了。。。。

March 22, 2026 · 1 min · santu

留言给博主