java内存溢出怎么解决错误怎么解决

> 应用jacob组件造成的内存溢出解决方案(java.lang.OutOfMemoryError: Java heap space)
应用jacob组件造成的内存溢出解决方案(java.lang.OutOfMemoryError: Java heap space)
peter621 & &
发布时间: & &
浏览:42 & &
回复:0 & &
悬赏:0.0希赛币
使用jacob组件造成的内存溢出解决方案(java.lang.OutOfMemoryError: Java heap space)
  都说内存泄漏是C++的通病,内存溢出是Java的硬伤,这个头疼的问题算是让我给碰到了。我在做的这个功能涉及到修改word文档,因为微软没有公开word源代码,所以直接用java流来读取word的后果是读出来的会是乱码,经过查资料得知可以使用poi和jacob来操作word,jacob使用起来相对poi要方便很多,因此我选择了jacob,Jacob 是Java-COM Bridge的缩写,它在Java与微软的COM组件之间构建一座桥梁。使用Jacob自带的DLL动态链接库,并通过JNI(Java Native Interface Java本地调用)的方式实现了在Java平台上对COM程序的调用。因为dll文件不能在linux上运行,而客户端只和linux交互,所以还需要一个windows服务器,这两个服务器不断的互相下载word,下载的频繁度最高连续达到十万次,以下是服务器之间的交互图:
  当功能实现了之后进行了一下测试,结果内存溢出了,于是就开始连查带改弄了半个月,检查打开的流有没有关闭,有没有大量使用静态变量,有没有大量使用String进行字符串拼接,遗憾的是没有找出问题在哪里(说明我写的代码质量还是不错的),也试图增加jvm内存,但增加jvm内存只能治标而不能治本,不是可靠的办法,经过大量查阅资料,得知com的线程回收不由java垃圾回收器进行处理,因此,每new一次jacob提供的类就要分配一定大小的内存给该操作,new出来的这个com对象在使用结束之后产生的垃圾java是无法回收的,new出来的对象越来越多,内存溢出就不可避免了,即使增加jvm内存也只是暂时的,迟早这些对象会把内存用完。既然java不能回收这些垃圾,那么com组件也应该提供了回收垃圾的方法,最后得知是ComThread.InitSTA()和ComThread.Release()方法,这两个方法其实就是初始化一个线程和结束这个线程,在创建com对象的时候初始化一个线程来运行这个对象,这个对象使用结束之后再结束线程,问题就这样得到解决了,程序连续运行一两天内存一直很平稳,弄了快一个月的问题终于解决了,以下是全部代码:
* @fileName MSWordManager.java
* @description 该类用于查找word文档指定位置并将图片插入
* @author wst
public class MSWordManager {
private Logger log = Logger.getLogger(MSWordManager.class);
// word文档
// word运行程序对象
private ActiveXC
// 所有word文档集合
// 选定的范围或插入点
public static int instanceSize=3;//一个线程存放的MSWordManager数量
public MSWordManager(int index) {
if (word == null) {
word = new ActiveXComponent("Word.Application");
//为true表示word应用程序可见
word.setProperty("Visible", new Variant(false));
if (documents == null){
documents = word.getProperty("Documents").toDispatch();
if(index==0){
ComThread.InitSTA();//初始化一个线程并放入内存中等待调用
* 打开一个已经存在的文档
* @param docPath 要打开的文档
* @param key 文本框的内容,根据该key获取文本框当前位置
* @author wst
public void openDocumentAndGetSelection(String docPath, String key) {
closeDocument();
// 打开文档
doc = Dispatch.call(documents, "Open", docPath).toDispatch();
// shapes集合
Dispatch shapes = Dispatch.get(doc, "Shapes").toDispatch();
// shape的个数
String Count = Dispatch.get(shapes, "Count").toString();
for (int i = 1; i &= Integer.parseInt(Count); i++) {
// 取得一个shape
Dispatch shape = Dispatch.call(shapes, "Item", new Variant(i)).toDispatch();
// 从一个shape里面获取到文本框
Dispatch textframe = Dispatch.get(shape, "TextFrame").toDispatch();
boolean hasText = Dispatch.call(textframe, "HasText").toBoolean();
if (hasText) {
// 获取该文本框对象
Dispatch TextRange = Dispatch.get(textframe, "TextRange").toDispatch();
// 获取文本框中的字符串
String str = Dispatch.get(TextRange, "Text").toString();
//获取指定字符key所在的文本框的位置
if (str != null && !str.equals("") && str.indexOf(key) & -1) {
//当前文本框的位置
selection = Dispatch.get(textframe, "TextRange").toDispatch();
// 情况文本框内容
Dispatch.put(selection, "Text", "");
}catch(Exception e){
log.error(e);
* 在当前位置插入图片
* @param imagePath 产生图片的路径
* @return 成功:true;失败:false
public boolean insertImage(String imagePath) {
Dispatch.call(Dispatch.get(selection, "InLineShapes").toDispatch(),"AddPicture", imagePath);
}catch(Exception e){
log.error(e);
//关闭文档
public void closeDocument() {
if (doc != null) {
Dispatch.call(doc, "Close");
//关闭全部应用
public void close(int index) {
if (word != null) {
Dispatch.call(word, "Quit");
selection =
documents =
if(index==instanceSize){
//释放占用的内存空间,因为com的线程回收不由java的垃圾回收器处理
ComThread.Release();
  问题解决了,虽然写的java程序没有什么问题,但是也学习到了一些如何防止内存溢出的知识,下面来看看我在网络找到的几种常见的内存溢出以及如何检测出内存溢出和出来办法。
  一、几种典型的内存泄漏
  我们知道了在Java中确实会存在内存泄漏,那么就让我们看一看几种典型的泄漏,并找出他们发生的原因和解决方法。
1 全局集合   在大型应用程序中存在各种各样的全局数据仓库是很普遍的,比如一个JNDI-tree或者一个session table。在这些情况下,必须注意管理储存库的大小。必须有某种机制从储存库中移除不再需要的数据。   通常有很多不同的解决形式,其中最常用的是一种周期运行的清除作业。这个作业会验证仓库中的数据然后清除一切不需要的数据。   另一种管理储存库的方法是使用反向链接(referrer)计数。然后集合负责统计集合中每个入口的反向链接的数目。这要求反向链接告诉集合何时会退出入口。当反向链接数目为零时,该元素就可以从集合中移除了。
2 缓存   缓存一种用来快速查找已经执行过的操作结果的数据结构。因此,如果一个操作执行需要比较多的资源并会多次被使用,通常做法是把常用的输入数据的操作结果进行缓存,以便在下次调用该操作时使用缓存的数据。缓存通常都是以动态方式实现的,如果缓存设置不正确而大量使用缓存的话则会出现内存溢出的后果,因此需要将所使用的内存容量与检索数据的速度加以平衡。   常用的解决途径是使用java.lang.ref.SoftReference类坚持将对象放入缓存。这个方法可以保证当虚拟机用完内存或者需要更多堆的时候,可以释放这些对象的引用。
3 类装载器  
Java类装载器的使用为内存泄漏提供了许多可乘之机。一般来说类装载器都具有复杂结构,因为类装载器不仅仅是只与"常规"对象引用有关,同时也和对象内部的引用有关。比如数据变量,方法和各种类。这意味着只要存在对数据变量,方法,各种类和对象的类装载器,那么类装载器将驻留在JVM中。既然类装载器可以同很多的类关联,同时也可以和静态数据变量关联,那么相当多的内存就可能发生泄漏。
  二、如何检测和处理内存泄漏   如何查找引起内存泄漏的原因一般有两个步骤:第一是安排有经验的编程人员对代码进行走查和分析,找出内存泄漏发生的位置;第二是使用专门的内存泄漏测试工具进行测试。   第一个步骤在代码走查的工作中,可以安排对系统业务和开发语言工具比较熟悉的开发人员对应用的代码进行了交叉走查,尽量找出代码中存在的数据库连接声明和结果集未关闭、代码冗余等故障代码。   第二个步骤就是检测Java的内存泄漏。在这里我们通常使用一些工具来检查Java程序的内存泄漏问题。市场上已有几种专业检查Java内存泄漏的工具,它们的基本工作原理大同小异,都是通过监测Java程序运行时,所有对象的申请、释放等动作,将内存管理的所有信息进行统计、分析、可视化。开发人员将根据这些信息判断程序是否有内存泄漏问题。这些工具包括Optimizeit Profiler,JProbe Profiler,JinSight , Rational 公司的Purify等。
1 检测内存泄漏的存在  这里我们将简单介绍我们在使用Optimizeit检查的过程。通常在知道发生内存泄漏之后,第一步是要弄清楚泄漏了什么数据和哪个类的对象引起了泄漏。   一般说来,一个正常的系统在其运行稳定后其内存的占用量是基本稳定的,不应该是无限制的增长的。同样,对任何一个类的对象的使用个数也有一个相对稳定的上限,不应该是持续增长的。根据这样的基本假设,我们持续地观察系统运行时使用的内存的大小和各实例的个数,如果内存的大小持续地增长,则说明系统存在内存泄漏,如果特定类的实例对象个数随时间而增长(就是所谓的“增长率”),则说明这个类的实例可能存在泄漏情况。   另一方面通常发生内存泄漏的第一个迹象是:在应用程序中出现了OutOfMemoryError。在这种情况下,需要使用一些开销较低的工具来监控和查找内存泄漏。虽然OutOfMemoryError也有可能应用程序确实正在使用这么多的内存;对于这种情况则可以增加JVM可用的堆的数量,或者对应用程序进行某种更改,使它使用较少的内存。   但是,在许多情况下,OutOfMemoryError都是内存泄漏的信号。一种查明方法是不间断地监控GC的活动,确定内存使用量是否随着时间增加。如果确实如此,就可能发生了内存泄漏。
2 处理内存泄漏的方法
  一旦知道确实发生了内存泄漏,就需要更专业的工具来查明为什么会发生泄漏。JVM自己是不会告诉您的。这些专业工具从JVM获得内存系统信息的方法基本上有两种:JVMTI和字节码技术(byte code instrumentation)。Java虚拟机工具接口(Java Virtual Machine Tools Interface,JVMTI)及其前身Java虚拟机监视程序接口(Java Virtual Machine Profiling Interface,JVMPI)是外部工具与JVM通信并从JVM收集信息的标准化接口。字节码技术是指使用探测器处理字节码以获得工具所需的信息的技术。  
Optimizeit是Borland公司的产品,主要用于协助对软件系统进行代码优化和故障诊断,其中的Optimizeit Profiler主要用于内存泄漏的分析。Profiler的堆视图就是用来观察系统运行使用的内存大小和各个类的实例分配的个数的。   首先,Profiler会进行趋势分析,找出是哪个类的对象在泄漏。系统运行长时间后可以得到四个内存快照。对这四个内存快照进行综合分析,如果每一次快照的内存使用都比上一次有增长,可以认定系统存在内存泄漏,找出在四个快照中实例个数都保持增长的类,这些类可以初步被认定为存在泄漏。通过数据收集和初步分析,可以得出初步结论:系统是否存在内存泄漏和哪些对象存在泄漏(被泄漏)。   接下来,看看有哪些其他的类与泄漏的类的对象相关联。前面已经谈到Java中的内存泄漏就是无用的对象保持,简单地说就是因为编码的错误导致了一条本来不应该存在的引用链的存在(从而导致了被引用的对象无法释放),因此内存泄漏分析的任务就是找出这条多余的引用链,并找到其形成的原因。查看对象分配到哪里是很有用的。同时只知道它们如何与其他对象相关联(即哪些对象引用了它们)是不够的,关于它们在何处创建的信息也很有用。   最后,进一步研究单个对象,看看它们是如何互相关联的。借助于Profiler工具,应用程序中的代码可以在分配时进行动态添加,以创建堆栈跟踪。也有可以对系统中所有对象分配进行动态的堆栈跟踪。这些堆栈跟踪可以在工具中进行累积和分析。对每个被泄漏的实例对象,必然存在一条从某个牵引对象出发到达该对象的引用链。处于堆栈空间的牵引对象在被从栈中弹出后就失去其牵引的能力,变为非牵引对象。因此,在长时间的运行后,被泄露的对象基本上都是被作为类的静态变量的牵引对象牵引。   总而言之, Java虽然有自动回收管理内存的功能,但内存泄漏也是不容忽视,它往往是破坏系统稳定性的重要因素。
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&&&湘教QS2-164&&增值电信业务经营许可证湘B2-摘要:本Blog主要为了阐述java.lang.OutOfMemoryError:PermGenspace可能产生的原因及解决方案。其中PermGen space是 Permanent Generationspace 的简写,表示 内存的永久保存区域 ,这块内存主要是被JVM 存放Class和Meta信息的,Class在被Loader时就会被放到PermGenspace中,它和存放类实例(Instance)的Heap区域不同, GC(Garbage Collection) 不会在主程序运行期对PermGen space 进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen space错误。
第一部分:原理解析(为什么为出现这样的原因)
第二部分:实际应用分析及解决方案参考
第三部分:安装版的Tomcat 怎样设置JAVA_OPTS
第四部分:怎样在eclipse 中设置TOMCAT 内存大小,解决启动时内存溢出 第一部分:原理解析:
String 其实是没有限制的,而是当String 太大了,超过JVM的自身的内存后会抛出
java.lang.OutOfMemoryError
错误,String 是没有长度限制的,而是有
JVM 的内存
限制了String 的长度。同时说明,并不会抛出任何Exception而只会抛出Error。
OutMemoryError
表明程序的设计差,或者遇到了超出编程人员所预想的大批量的数据。
不管哪种情况,都只有下面这几种解决办法。它们是:
A 、设计人员重新设计程序,不致使程序一次载入所有的数据。
B 、数据可以分割成更小的块。
C 、可以为程序分配更多的内存。
D 、为Java 虚拟机提供更多的内存。
一般都是发生在
开启大型档案或跟数据库一次加载太多的数据
,造成&Out Of MemoryError& 的状况,这时就大概要计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。另一种状况平时比较难查觉。就是&
Servlet& 或&JSP& 的&Container&突然同时上线人数爆增
,也相对造成内存需求不足,所以也必须要计算出程序所需的数据量* 同时上线人数,来设定内存的需求量。(如果要有最佳化的值,最好是配合&gc&做调校)
当&CPU& 速度愈快,内存的最小需求量也就必需愈大。原因是&CPU&愈快,短时间内能处理的数据量也就愈大,所以在&java&做&GC&之前,可能已经内存已经消耗完了,所以&CPU&的速度也是内存初始需求量的重要因素之一。
解决 方法:
修改 JAVA_OPTS=&-Xms1024m-Xmx1024m&
&或更大,根据系统内存情况
jsp 开发中有关java.lang.OutOfMemoryError 的产生及解决方法&
第二部分:实际应用场景及解决方案参考(如下是服务器版——解压缩版本):
预准备(各种环境中文件的位置)
【 Windows 】在 catalina.bat 的第一行增加:
set JAVA_OPTS=-Xms512m -Xmx900m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m
【非 Windows 】在 catalina.sh 的第一行增加: &
JAVA_OPTS=-Xms512m -Xmx900m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m
一、java.lang.OutOfMemoryError: PermGenspace
PermGen space 的全称是PermanentGeneration space, 是指内存的永久保存区域,这块内存主要是
被JVM 存放Class和Meta信息
的,Class 在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,
GC(Garbage Collection) 不会在主程序运行期对PermGen space 进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGenspace错误
,这种错误常见在web 服务器对JSP进行precompile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。
解决方法: 手动设置 大小
修改TOMCAT_HOME/bin/catalina.sh在“echo &Using CATALINA_BASE:&&$CATALINA_BASE&”上面加入以下行:JAVA_OPTS=&-server -XX:PermSize=64M -XX:MaxPermSize=128m 建议:将相同的第三方jar文件移置到tomcat/shared/lib目录下,这样可以达到减少jar 文档重复占用内存的目的。
二、java.lang.OutOfMemoryError:Java heap space
设置:堆的设置是指java程序运行过程中JVM可以调配使用的内存空间的设置.JVM在启动的时候会自动设置Heap size的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置。Heap size 的大小是Young Generation 和Tenured Generaion 之和。
在JVM 中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息。 提示二:
Heap Size 最大不要超过可用物理内存的80 %,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。
解决方法:手动设置Heap size
修改TOMCAT_HOME/bin/catalina.sh在“echo &UsingCATALINA_BASE:&&&&& $CATALINA_BASE&”上面加入以下行:JAVA_OPTS=&-server -Xms800m -Xmx800m&&&&&-XX:MaxNewSize=256m&
三、实例,以下给出1G 内存环境下java jvm 的参数设置参考:
JAVA_OPTS=&-server -Xms800m-Xmx800m&&&& -XX:PermSize=64M -XX:MaxNewSize=256m-XX:MaxPermSize=128m -Djava.awt.headless=true &
大家都知道,JAVA 程序启动时都会JVM都会分配一个初始内存和最大内存给这个应用程序。这个初始内存和最大内存在一定程度都会影响程序的性能。比如说在应用程序用到最大内存的时候,JVM是要先去做垃圾回收的动作,释放被占用的一些内存。&&&&&&&&& 所以想调整Tomcat的启动时初始内存和最大内存就需要向JVM声明,一般的JAVA程序在运行都可以通过中-Xms -Xmx来调整应用程序的初始内存和最大内存:& &&&&&&&&& 如:java -Xms64m&&& -Xmx128m&&& a.jar. tomcat的启动程序是包装过的,不能直接使用java -X..... tomcat.*来改变内存的设置。
在Tomcat 在改变这个设置有两种方法:
就需要在环境变量中加上TOMCAT_OPTS, CATALINA_OPTS 两个属性,&&&&&&&&& 如 SET&&& CATALINA_OPTS= -Xms64m -Xmx512m; &&&&&&&&& ms是最小的,mx是最大,64m, 512m分别是指内存的容量. 2.&&&&& 修改Catalina.bat文件 &&&&&&&& 在166行“rem Execute Java with the applicable properties ”以下每行 %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS%-Djava.endorsed.dirs=&%JAVA_ENDORSED_DIRS%& -classpath&%CLASSPATH%& -Dcatalina.base=&%CATALINA_BASE%&-Dcatalina.home=&%CATALINA_HOME%&-Djava.io.tmpdir=&%CATALINA_TMPDIR%& %MAINCLASS% %CMD_LINE_ARGS%%ACTION% 中的%CATALINA_OPTS% 替换成-Xms64m-Xmx512m 第三部分:如果是安装版的tomcat怎样设置JAVA_OPTS
JAVA_OPTS=&-Xms128M-Xmx512M -XX:PermSize=128M -XX:MaxPermSize=512M&
tomcat 如果是通过windows 服务启动,执行的是bin/tomcat.exe.他读取注册表中的值,而不是catalina.bat的设置.
修改注册表HKEY_LOCAL_MACHINE/SOFTWARE/Apache Software Foundation/Procrun2.0/Tomcat6/Parameters/JavaOptions原值为-Dcatalina.home=E:/Tomcat 6.0 -Dcatalina.base=E:/Tomcat 6.0 -Djava.endorsed.dirs=E:/Tomcat 6.0/common/endorsed -Djava.io.tmpdir=E:/Tomcat 6.0/temp -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file=E:/Tomcat6.0/conf/logging.properties
在后面增加即可:
-XX:PermSize=128M
-XX:MaxPermSize=512M
必须要分行写。
最终效果如下:(细节注解:将相应的信息加入Java Options 输入框的后面即可)
第四部分:eclipse 中设置TOMCAT 内存大小 ,解决启动时内存溢出有时在ECLIPSE中启动TOMCAT会出现内存溢出和转换错误等莫名奇妙的错误,这些很有可能是内存不够引起的,这时可以在设置中找到Server然后找到Tomcat找到对应的版本。
方法一:永久设置 JVM 相应的参数值:
通过Windows下的Preferences找到Tomcat中的JVM Settings中的Append to JVMParameters进行相应的参数设置:-Xms128m -Xmx512m& -XX:PermSize=256M-XX:MaxNewSize=128m -XX:MaxPermSize=512m如下图所示:
方法二:临时设置相应的参数——在 eclipse 中进行如下步骤设置:
1、点击eclipse上的debug图标旁边的下拉箭头2、然后选择Debug &Configurations,3、系统弹出设置tomcat配置页面,在Argument中末尾添加参数中的VM arguments中追加:-Xms256M-Xmx512M -XX:PermSize=256m -XX:MaxPermSize=512m 参数的意思 -vmargs:说明后面是VM的参数 -Xms40m:虚拟机占用系统的最小内存 -Xmx256m:虚拟机占用系统的最大内存 -XX:PermSize:最小栈内存大小。一般报内存不足时,都是说这个太小,堆空间剩余小于5%就会警告,建议把这个稍微设大一点,不过要视自己机器内存大小来设置 -XX:MaxPermSize:最大栈内存大小。这个也适当大些 -Xmx512M的5%为25.6M,理论上要求-Xmx的数值与-XX:MaxPermSize必须大于25.6M
参考文献: http://blog.csdn.net/hdfyq/article/details/5856284
http://blog.csdn.net/w/article/details/7878404
/blog/1574040
http://116.255.173.144/?c=article&a=read&id=59498 http://my.oschina.net/colorleaf/blog/175581Java内存溢出相关问题_Linux编程_Linux公社-Linux系统门户网站
你好,游客
Java内存溢出相关问题
来源:Linux社区&
作者:Linux
一、内存溢出类型
1、java.lang.OutOfMemoryError: PermGen space
JVM管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的。它和堆不同,运行期内GC不会释放空间。如果web app用了大量的第三方jar或者应用有太多的class文件而恰好MaxPermSize设置较小,超出了也会导致这块内存的占用过多造成溢出,或者tomcat热部署时侯不会清理前面加载的环境,只会将context更改为新部署的,非堆存的内容就会越来越多。
2、java.lang.OutOfMemoryError: Java heap space
第一种情况是个补充,主要存在问题就是出现在这个情况中。其默认空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。如果内存剩余不到40%,JVM就会增大堆到Xmx设置的值,内存剩余超过70%,JVM就会减小堆到Xms设置的值。所以服务器的Xmx和Xms设置一般应该设置相同避免每次GC后都要调整虚拟机堆的大小。假设物理内存无限大,那么JVM内存的最大值跟操作系统有关,一般32位机是1.5g到3g之间,而64位的就不会有限制了。
注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。
垃圾回收GC的角色
JVM调用GC的频度还是很高的,主要两种情况下进行垃圾回收:
当应用程序线程空闲;另一个是java内存堆不足时,会不断调用GC,若连续回收都解决不了内存堆不足的问题时,就会报out of memory错误。因为这个异常根据系统运行环境决定,所以无法预期它何时出现。
根据GC的机制,程序的运行会引起系统运行环境的变化,增加GC的触发机会。
为了避免这些问题,程序的设计和编写就应避免垃圾对象的内存占用和GC的开销。显示调用System.GC()只能建议JVM需要在内存中对垃圾对象进行回收,但不是必须马上回收,
一个是并不能解决内存资源耗空的局面,另外也会增加GC的消耗。
二、JVM内存区域组成
简单的说java中的堆和栈
java把内存分两种:一种是栈内存,另一种是堆内存
1。在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配;
2。堆内存用来存放由new创建的对象和数组
在函数(代码块)中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量所分配的内存空间;在堆中分配的内存由java虚拟机的自动垃圾回收器来管理
堆的优势是可以动态分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的。缺点就是要在运行时动态分配内存,存取速度较慢;
栈的优势是存取速度比堆要快,缺点是存在栈中的数据大小与生存期必须是确定的无灵活性。
java堆分为三个区:New、Old和Permanent
GC有两个线程:
新创建的对象被分配到New区,当该区被填满时会被GC辅助线程移到Old区,当Old区也填满了会触发GC主线程遍历堆内存里的所有对象。Old区的大小等于Xmx减去-Xmn
java栈存放
栈调整:参数有+UseDefaultStackSize -Xss256K,表示每个线程可申请256k的栈空间
每个线程都有他自己的Stack
三、JVM如何设置虚拟内存
提示:在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息。
提示:Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。
提示:JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。
默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。
提示:假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。
简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,
这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了
提示:注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。
提示:设置NewSize、MaxNewSize相等,"new"的大小最好不要大于"old"的一半,原因是old区如果不够大会频繁的触发"主" GC ,大大降低了性能
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;
由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。
解决方法:手动设置Heap size
修改TOMCAT_HOME/bin/catalina.bat
在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:
JAVA_OPTS="-server -Xms800m -Xmx800m -XX:MaxNewSize=256m"
四、性能检查工具使用
定位内存泄漏:
JProfiler工具主要用于检查和跟踪系统(限于Java开发的)的性能。JProfiler可以通过时时的监控系统的内存使用情况,随时监视垃圾回收,线程运行状况等手段,从而很好的监视JVM运行情况及其性能。
1. 应用服务器内存长期不合理占用,内存经常处于高位占用,很难回收到低位;
2. 应用服务器极为不稳定,几乎每两天重新启动一次,有时甚至每天重新启动一次;
3. 应用服务器经常做Full GC(Garbage Collection),而且时间很长,大约需要30-40秒,应用服务器在做Full GC的时候是不响应客户的交易请求的,非常影响系统性能。
因为开发环境和产品环境会有不同,导致该问题发生有时会在产品环境中发生,通常可以使用工具跟踪系统的内存使用情况,在有些个别情况下或许某个时刻确实是使用了大量内存导致out of memory,这时应继续跟踪看接下来是否会有下降,
如果一直居高不下这肯定就因为程序的原因导致内存泄漏。
五、不健壮代码的特征及解决办法
1、尽早释放无用对象的引用。好的办法是使用临时变量的时候,让引用变量在退出活动域后,自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄露。
对于仍然有指针指向的实例,jvm就不会回收该资源,因为垃圾回收会将值为null的对象作为垃圾,提高GC回收机制效率;
2、我们的程序里不可避免大量使用字符串处理,避免使用String,应大量使用StringBuffer,每一个String对象都得独立占用内存一块区域;
String str = "aaa";
String str2 = "bbb";
String str3 = str + str2;//假如执行此次之后str ,str2以后再不被调用,那它就会被放在内存中等待Java的gc去回收,程序内过多的出现这样的情况就会报上面的那个错误,建议在使用字符串时能使用StringBuffer就不要用String,这样可以省不少开销;
3、尽量少用静态变量,因为静态变量是全局的,GC不会回收的;
4、避免集中创建对象尤其是大对象,JVM会突然需要大量内存,这时必然会触发GC优化系统内存环境;显示的声明数组空间,而且申请数量还极大。
这是一个案例想定供大家警戒
使用jspsmartUpload作文件上传,运行过程中经常出现java.outofMemoryError的错误,
检查之后发现问题:组件里的代码
m_totalBytes = m_request.getContentLength();
m_binArray = new byte[m_totalBytes];
问题原因是totalBytes这个变量得到的数极大,导致该数组分配了很多内存空间,而且该数组不能及时释放。解决办法只能换一种更合适的办法,至少是不会引发outofMemoryError的方式解决。
5、尽量运用对象池技术以提高系统性能;生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。
6、不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。可以适当的使用hashtable,vector 创建一组对象容器,然后从容器中去取那些对象,而不用每次new之后又丢弃
7、一般都是发生在开启大型文件或跟数据库一次拿了太多的数据,造成 Out Of Memory Error 的状况,这时就大概要计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。
相关资讯 & & &
& (04月22日)
& (03/07/:22)
& (05月21日)
& (07/09/:16)
& (11/08/:29)
图片资讯 & & &
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款

我要回帖

更多关于 用友内存溢出怎么解决 的文章

 

随机推荐