博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
解密Java内存溢出之持久代
阅读量:5040 次
发布时间:2019-06-12

本文共 2184 字,大约阅读时间需要 7 分钟。

垃圾回收是Java程序员了解最少的一部分。他们认为Java虚拟机接管了垃圾回收,因此没必要去担心内存的申请,分配等问题。但是随着应用越来越复杂,垃圾回收也越来越复杂,一旦垃圾回收变的复杂,应用的性能将会大打折扣。所以,Java程序员了解垃圾回收的机制并且知道怎样解决“内存溢出”问题会有很大的益处。在Java中,有两个非常普遍的内存溢出问题。一个是堆内存溢出,另一个是持久代内存溢出。

持久代和类加载器

       Java对象是java 类的实例。每当创建一个Java对象时,Java虚拟机都会创建该对象的内部引用并且保存在堆中。如果一个类是第一次访问,那么它必须通过Java虚拟机加载进来。类加载是定位,寻找,加载class文件和解析class文件结构的过程。类加载器负责确保加载正确的class文件。Java程序里面每一个class文件需要被同一个类加载加载。类加载器是 java.lang.ClassLoader 类的实例。目前为止,类加载器是在持久代空间里面加载类的。

       Java虚拟机也创建了Java类的内部引用保存在持久代。在垃圾回收期间,Java对象和类都当做对象处理并且以同样的方式回收。最初Java对象和类都是保存在堆中。

一个性能优化措施:一旦持久代创建后,就会把classes放入里面。Classes是Java虚拟机的部分实现,我们不应该用我们的数据结构填满Java堆。持久代包含以下类信息:

  • 类方法
  • 类名称
  • 常量池信息
  • 对象数组和与类相关的类型数组
  • 被Java虚拟机使用的内部对象
  • 编译器用于优化的信息

现在我们知道了持久代是什么,接下来看看在这块会是什么原因引起内存问题。

持久代空间

       当Java虚拟机需要加载定义的一个新class,但是在持久代中没有足够的空间就会抛出‘Java.Lang.OutOfMemoryError: PermGen Space’异常。默认分配给持久代的大小在server模式下是64MB ,在client模式下是32MB 。这就有两个原因可能会引起持久代内存溢出问题的发生。

第一个原因可能是你应用或者服务器已经有非常多的class在你的持久代中,已经不能容纳所有的class了。

-XX:MaxPermSize=XXXM

        如果是因为大量的class导致持久代的空间的不足引起的问题,那么你可以增加持久代的大小通过–XX:MaxPermSize=XXm  参数。这将增加持久代的可用空间来保存class。看起来像这样: -XX:MaxPermSize=256m

-XX:+CMSClassUnloadingEnabled

       这个参数表示在使用CMS垃圾回收机制的时候是否启用类卸载功能。默认这个是设置为不启用的,所以你想启用这个功能你需要在Java参数中明确的设置下面的参数:

-XX:+CMSClassUnloadingEnabled

如果你启用了CMSClassUnloadingEnabled ,垃圾回收会清理持久代,移除不再使用的classes。这个参数只有在   也启用的情况下才有用。参数如下:

-XX:+UseConcMarkSweepGC

-XX:+CMSPermGenSweepingEnabled

       这个参数表示是否会清理持久代。默认是不清理的,因此我们需要明确设置这个参数来调试持久代内存溢出问题。这个参数在Java6中被移除了,因此你需要使用 -XX:+CMSClassUnloadingEnabled 如果你是使用Java6或者后面更高的版本。那么解决持久代内存大小问题的参数看起来会是下面这样子:

-XX:MaxPermSize=128m -XX:+UseConcMarkSweepGC XX:+CMSClassUnloadingEnabled

内存泄露

     第二个原因可能是内存泄露。那么加载的类怎样变成不用的呢?

     在Java中通常class是永久存在的。一旦class被加载,他们就呆在内存中,即使服务器上的应用停掉了。像cglib这样可以动态产生class的类库会使用很多持久代空间,因为它动态的创建很多class。频繁的使用在运行时创建的代理类。当一个类定义可以为多个实例重用时很容易创建新的代理类。

       Sping和Hibernate经常会代理某些class。这些代理的class是通过类加载器加载的。产生的类定义如果一直不回收就会导致持久代空间很快就满了。

       你需要确定是不是内存泄露引起的持久代空间的问题,同时解决它。增加持久代空间大小将不会有用,这只会延迟它的发生,因为在某个时间点持久代还是会被填满。

       如果你正在使用tomcat遇到了内存泄露问题,最新版本的tomcat有能力处理一些内存泄露问题。详细请看:

 总结

       一旦你遇到了持久代内容溢出问题,你需要找出这个问题是因为加载了大量的class文件还是内存泄露引起的。如果是因为class的数量过多,你可以增加持久代分配的空间大小来解决这个问题。如果是因为内存泄露,你需要引起内存泄露的根源所在并且定位它。一些框架像cglib,Spring,Hibernate会创建大量的动态类,因此对于使用这些框架的应用最好是分配多一点的持久代空间。

原文链接: 

转载于:https://www.cnblogs.com/lgqboke/p/5809589.html

你可能感兴趣的文章
TensorFlow2.0矩阵与向量的加减乘
查看>>
NOIP 2010题解
查看>>
javascript中的each遍历
查看>>
String中各方法多数情况下返回新的String对象
查看>>
浅谈tcp粘包问题
查看>>
UVA11524构造系数数组+高斯消元解异或方程组
查看>>
排序系列之——冒泡排序、插入排序、选择排序
查看>>
爬虫基础
查看>>
jquery.lazyload延迟加载图片第一屏问题
查看>>
HDU 1011 Starship Troopers (树形DP)
查看>>
手把手教你写DI_1_DI框架有什么?
查看>>
.net常见的一些面试题
查看>>
OGRE 源码编译方法
查看>>
上周热点回顾(10.20-10.26)
查看>>
C#正则表达式引发的CPU跑高问题以及解决方法
查看>>
云计算之路-阿里云上:“黑色30秒”走了,“黑色1秒”来了,真相也许大白了...
查看>>
APScheduler调度器
查看>>
设计模式——原型模式
查看>>
【jQuery UI 1.8 The User Interface Library for jQuery】.学习笔记.1.CSS框架和其他功能
查看>>
如何一个pdf文件拆分为若干个pdf文件
查看>>