Java内存不足之PermGen space错误探究
一.Java 程序的运行机制与普通程序,如C或C++ 程序的运行机制有很大的区别。
普通程序运行之前必须首先编译成可执行的二进制码或机器码。机器码是与底层的硬件结构相关的,即使书写源代码的时候没有利用平台特定的扩展语言,如特定的文件访问或图形用户界面,生成的机器码仍然被绑定到一个特定的硬件平台,从而只能运行在那个体系结构上,也就是说,为Sun工作站编译的机器码不能运行在PC机上,为PC机编译的机器码不能运行在苹果机上,以此类推。
与此相反,Java源代码不是为某种特定平台编译的,而是编译成与平台无关的字节码(Byte Code),这种字节码叫做Java Class(Java 类文件)。在任何一种操作系统平台上的字节码都是一样的,因此都可以在任何支持Java 虚拟机(JVM)的计算机上运行。JVM 直接受操作系统控制(而不是Java程序直接受操作系统控制),它负责将字节码转换成在特定平台上能够运行的机器码。正是由于这个原因,Java做到了“write once, run anywhere”(书写一次,到处运行)
运行Java程序时,首先需要由JVM把Java class加载到JVM里面。通常情况下,我们不会去关注JVM的内部工作细节而只是直接拿来使用。然而,作为一个Java开发人员,你经常会遇到与内存相关的性能问题。这个问题最可怕的就是OutOfMemoryError:PermGen space错误。
这个错误通常会在以下三种情况下发生(服务器以Tomcat为例):
(1)应用程序加载了大量的类。
(2)在单一的Tomcat实例下运行多个Web应用程序。
(3)在运行的Tomcat实例中反复“热部署”Web应用程序。
下面我们对该错误进行探究,分析该错误的常见原因,并给出避免这一错误的解决办法。
1.JVM 的内存结构
为了理解这一错误,我们必须了解JVM的内存是如何构造的。
JVM有两个内存区域,一个是堆(heap),另一个是栈(stack)。局部的变量和方法驻留在栈里面,其余的一切都驻留在堆中。
Java的堆又进一步按照区域进行组织,这些区域被称为generation。一个对象在JVM存在的时间越长,它被升迁到老的generation中的几率就越高。年轻的generation要比老的generation更多、更容易地被垃圾回收。同时还存在一些单独的堆空间,被称为永久保存区域(permanent generation),它们不属于Java堆的一部分,用来存放类和类的描述。
类加载器的工作是不断地部署和取消部署Java类。例如,将一个Web应用程序部署到Web服务器或取消部署。在Web服务器上,所有应用程序都有自己的类加载器,部署或取消部署应用程序时,它的类定义和类加载器分别投入到永久保存区域中或者从永久保存区域中删除。
2.OutOfMemoryError: PermGen space
当永久保存区域的空间耗尽时OutOfMemoryError: PermGen space就会发生,这个错误一般是由于内存泄漏导致的。所谓内存泄漏,是指java类和类加载器在被取消部署后不能被垃圾回收。怎么会发生这种情况呢?举个例子:假如我们有一个Student类,这个类是Web应用程序jar包的一部分,同时在Web服务器的lib文件夹中包含了某种日志框架,其中有一个Log类提供register方法调用,从而使得别的类通过注册就可以使用日志功能。如果Student类被注册了,那么Log类就开始拥有了一个对Student对象的引用(reference)。当Student类取消部署时,它仍然是注册Log类的,Log类仍然拥有对Student对象的引用,因此,Student对象永远不会被垃圾回收。此外,由于Student对象拥有一个对它的ClassLoader的引用,所以ClassLoader本身永远也不会被垃圾回收,从而导致由它加载的所有类都不会被回收。
一个更为典型的例子是使用代理对象。Spring和Hibernate常常为某些类生成代理类,这些代理类也是通过类加载器加载的,并且存储在永久保存区域的堆空间,它们永远不会被丢弃,从而会导致永久保存区域的堆空间被填满。
3.如何避免永久保存区域内存不足
3.1 增加PermGen堆的最大尺寸
当遇到java.lang.OutOfMemoryError:PermGen space错误时,我们可以做的第一件事情是增加永久保存区域的最大尺寸,该尺寸的缺省设置是64 M,我们可以将它设置成128 M以上。这个工作不能通过常规的JVM参数 -Xms(设置初始堆大小)和-Xmx(设置最大堆大小)来完成,因为前面已经提到,永久保存区域完全独立于普通的Java堆,这些参数是用来设置普通的Java堆的。不过也有类似参数用于设置永久保存区域的规模:
java -XX:MaxPermSize=128 M
该设置将永久保存区域设置为128 M,这个大小是默认设置的两倍。
对于Tomcat服务器,则需要修改TOMCAT_HOME/bin/catalina.sh
SET JAVA_OPTS=-XX:PermSize=64 M -XX:MaxPermSize=128 M
3.2 避免使用静态字段
确保在编写Java类时,不要使用静态变量作为对其他对象的引用。
3.3使用JDK动态代理,而不是CGLIB代理
一些第三方的框架,如CGLIB会吞食大量的PermGen。因此,当遇到PermGen错误时,应尽快升级cglib到最新版;改用JDK动态代理,也是一个不错的选择。
3.4更新到最新版本Hibernate3.2
此外,新版本的Hibernate不再使用CGLIB作为字节码提供者了,所以及时升级Hibernate,会大大降低出错的机会。
3.5共用的jar文件放到共享目录下
如果在服务器上同时发布了多个应用,那么应该把共用的jar文件放到所有应用都可以访问的目录下。针对Tomcat而言,如果Tomcat下面有多个应用,应尽可能地把lib目录下共用的jar文件放到Tomcat的common\lib或shared\lib下,以避免重复发布,发布速度和运行速度上也会有所提升。
4.结束语
内存不足问题是潜伏较深的问题,且不容易解决。一般情况下,当发生该错误的时候,需要确定为什么某些类不被垃圾回收,只有这样做才能够消除这个错误。
本文摘自中国论文网,原文地址:http://www.xzbu.com/8/view-3801715.htm
Java内存不足之PermGen space错误探究的更多相关文章
- 出现 java.lang.OutOfMemoryError: PermGen space 错误的原因及解决方法
一.原因及解决方法[1] 1.原因:堆内存的永久保存去区内存分配不足(缺省默认为64M),导致内存溢出错误. 2.解决方法:重新分配内存大小,-Xms1024M -Xmx2048M -XX:PermS ...
- windows系统bat方式启动tomcat出现java.lang.OutOfmemoryError:PermGen Space 错误
1.问题情景: 在部署项目时,将两个应用部署到同一个tomcat下,通过startup.bat启动服务时,控制台出现出现java.lang.OutOfmemoryError:PermGen Space ...
- Tomcat死机报OutOfMemoryError: PermGen space错误
最近,用户没怎么使用系统,页面就卡死,访问不了.仔细一看是Tomcat假死,好几次都这样.重启也慢的很,很着急.最后,看了下 conf/logs 里的配置文件,发现是 OutOfMemoryError ...
- PermGen space错误解决方法
在看下文之前,首先要确认意见事情,就是你是怎样启动tomcat的,我们在平时的开发环境其中,都是通过startup.bat方式启动tomcat的,那么你依照以下的方式,去改动/bin/catalina ...
- tomcat内存溢出之PermGen space
线上一台web服务器不能正常访问了,检查了一下,tomcat进程还在,就是web不能正常访问,重启一下tomcat恢复正常,查询日志,发现提示内存溢出,如下图: java.lang.OutOfMemo ...
- tomcat启动出现PermGen space错误
今天部署项目时,出现了jvm内存溢出的问题,显示PermGen space错误. 经过不断的努力,终于解决出来了. 步骤如下: 在eclipse中菜单栏run-->RunConfigurati ...
- IDEA控制台问题:java lang OutOfMemoryError:PermGen space
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域. OutOfMemoryError: PermGen space从表面上看就是内存溢出, ...
- JMeter-java.lang.OutOfMemoryError: PermGen space错误
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被 ...
- 在Eclipse中运行Jboss时出现java.lang.OutOfMemoryError:PermGen space及其解决方法
在Eclipse中运行Jboss时出现java.lang.OutOfMemoryError:PermGen space及其解决方法 在Eclipse中运行Jboss时,时间太长可能有时候会出现java ...
随机推荐
- java 正则表达式验证邮箱格式是否合规 以及 正则表达式元字符
package com.ykmimi.testtest; /** * 测试邮箱地址是否合规 * @author ukyor * */ public class EmailTest { public s ...
- stm32 ADC使用方法
void Adc_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_AP ...
- MongoVUE的Collections数据不显示的解决方法
问题描述: 使用 mongoDB数据库, 数据添加成功了,使用命令行能查询出来,但在MongoVUE 中数据却不显示 (我使用的是 mongoDB 3.4 的版本) 原因:引擎问题,只要降到2.X版 ...
- BM25 调参调研
1. 搜索 ES 计算文本相似度用的 BM25,参数默认,不适合电商场景,可调整 BM25 参数使其适用于电商短文本场景 2. k1.b.tf.L.tfScore 的关系如下图红框内所示(注:这里的 ...
- 精伦盒子H1,插上USB,找不到对应的文件路径
看USB的灯闪的挺正常的, 但就是不知道,该怎么mount 上去. 查了UDEV的资料, 发觉这个盒子虽然没有 udevmonitor命令, 却可以用 udevadm monitor 来监视udev ...
- 在浏览器外打开PDF文档
One function you might find annoying with PDFs and PDF Readers is that when you click on a link to a ...
- 雷林鹏分享:Ruby 字符串(String)
Ruby 字符串(String) Ruby 中的 String 对象存储并操作一个或多个字节的任意序列,通常表示那些代表人类语言的字符. 最简单的字符串是括在单引号(单引号字符)内.在引号标记内的文本 ...
- 4-3 atom订阅源
部分章节还没有实做练习. 网上购买了安道的Rails指南中文版.联系了这个作者问了一个问题Rails5的翻译问题. try(), 判断是否存在,不存在的话返回nil.例子:pasting @perso ...
- PHP函数总结 (四)
<?php/** * 引用参数: * 1.PHP默认按值传递参数,父程序(调用函数)与子程序(函数)的数值分别存储与不同的内存区块: * 2.引用传递参数,加符号 & :它是把父程序的数 ...
- Ubuntu中vi命令的编辑模式异常
今天更改Ubuntu软件源的时候,进入源文件的编辑模式时,发现删除键和编辑都不能正常使用,百度之后,知道是由于Ubuntu预装的是vim-tiny,而我们需要使用vim-full.在此记录下该问题以便 ...