13326882788
您的当前位置:东莞seo首页 > 知识博客 > java heap space解决方法和JVM参数设置

java heap space解决方法和JVM参数设置

时间:21-08-25 15:49

在JVM中如果98%的时间是用于GC(Garbage Collection)且可用的 Heap size 不足2%的时候将抛出异常信息,java.lang.OutOfMemoryError: Java heap space。 

所以产生这个异样的原因通常有两种:

1.程序中出现了死循环

2.程序占用内存太多,超过了JVM堆设置的最大值。

    对于第一种情况,需要自己查看程序代码,这里不再多说。

    第二种情况,我们手工扩大JVM堆的参数设置。JVM堆的设置是指java程序运行过程中JVM可以调配使用的内存空间的设置。在JVM启动时,JVM堆会自动设置heap size值。通常情况下,初始空间(即-Xms)默认值是物理内存的1/64,最大空间是物理内存的1/4。可以利


用JVM提供的-Xmn -Xms -Xmx等选项可进行设置。这里对各个参数的意义解释一下:

-Xms:初始值 

-Xmx:最大值 

-Xmn:最小值 

Heap Size的设置不宜太小,也不宜太大。若设置太小程序的响应速度会变慢了,因为GC占用了更多的时间,而应用分配到的执行时间较少。太大也会造成空间的浪费,而且也会影响其他程序的正常运行。Heap Size 最大最好不要超过可用物理内存的80%。建议将-Xms和


-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。

设置的方法主要有以下几个: 

1.就是在执行JAVA类文件时加上这个参数,其中className是需要执行的确类名。(包括包名)如:java -Xms32m -Xmx800m className 这个不仅解决问题了,而且执行的速度比没有设置的时候快很多。如果是开发测试,也可以再eclipse中直接设置。Eclipse 


->run -arguments 中的VM arguments 中输入-Xms32m -Xmx800m这个参数就可以了。 

2.可以在windows更改系统环境变量加上JAVA_OPTS=-Xms64m -Xmx512m。

3.如果用的tomcat,在windows下,可以在C:tomcat5.5.9bincatalina.bat(具体路径根据自己tomcat的位置而定) 中加上:set JAVA_OPTS=-Xms64m -Xmx256m (大小依自己内存而定)位置在: rem Guess CATALINA_HOME if not defined 这行的下面加合适. 

4.如果是linux系统Linux 在{tomcat_home}/bin/catalina.sh的前面,加 set JAVA_OPTS='-Xms64 -Xmx512'

因为程序要从数据读取近10W行记录处理,当读到9W的时候就出现 java.lang.OutOfMemoryError: Java heap space 这样的错误。

 在网上一查可能是JAVA的堆栈设置太小的原因。

 跟据网上的答案大致有这两种解决方法:

1、设置环境变量

set JAVA_OPTS= -Xms32m -Xmx512m

可以根据自己机器的内存进行更改,但本人测试这种方法并没有解决问题。可能是还有哪里需要设置。

2、java -Xms32m -Xmx800m className

就是在执行JAVA类文件时加上这个参数,其中className是需要执行的确类名。(包括包名)

 这个解决问题了。而且执行的速度比没有设置的时候快很多。

如果在测试的时候可能会用Eclispe 这时候就需要在Eclipse ->run -arguments 中的VM arguments 中输入-Xms32m -Xmx800m这个参数就可以了。

java.lang.OutOfMemoryError: Java heap space 

 ===================================================

使用Java程序从数据库中查询大量的数据时出现异常:

java.lang.OutOfMemoryError: Java heap space

在JVM中如果98%的时间是用于GC且可用的 Heap size 不足2%的时候将抛出此异常信息。

JVM堆的设置是指java程序运行过程中JVM可以调配使用的内存空间的设置.

JVM在启动的时候会自动设置Heap size的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置。

 例如:java -jar -Xmn16m -Xms64m -Xmx128m MyApp.jar

如果Heap Size设置偏小,除了这些异常信息外,还会发现程序的响应速度变慢了。GC占用了更多的时间,而应用分配到的执行时间较少。


Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。

Heap size的 -Xms -Xmn 设置不要超出物理内存的大小。否则会提示“Error occurred during initialization of VM Could not reserve enough space for object heap”。


==========================================================

经过一个晚上的努力终于完成了一个文件替换指定字符串的程序,但是由于我要替换的全站程序html文件太多,所以eclipse下边老是在一个目录结束后 报出java.lang.OutOfMemoryError: Java heap space的异常,然后就崩溃了。


我一想肯定是频繁操作造成来不及回收,于是在每个循环之后加上一个Thread.sleep(1000),发现还是到那个目录下就死掉,于是把 1000改成5000,还是到那里死掉,我想可能不是来不及回收这么简单,或许sun 的JVM里边刚好对于这种情况不释放也有可能。

 接着我又把启动的参数添上一个 -Xmx256M,这回就可以了。


想一想,还是对于垃圾回收的原理不太了解,就在网上查了一下,发现了几篇不错的文章。


http://java.ccidnet.com/art/3539/20060314/476073_1.html

http://www.pconline.com.cn/pcedu/empolder/gj/java/0509/701281.html



还有:Java堆的管理—垃圾回收提到一下几点,很不错,或许可以作为写程序时候的准则:


  (1)不要试图去假定垃圾收集发生的时间,这一切都是未知的。比如,方法中的一个临时对象在方法调用完毕后就变成了无用对象,这个时候它的内存 就可以被释放。


  (2)Java中提供了一些和垃圾收集打交道的类,而且提供了一种强行执行垃圾收集的方法--调用System.gc(),但这同样是个不确定 的方法。Java 中并不保证每次调用该方法就一定能够启动垃圾收集,它只不过会向JVM发出这样一个申请,到底是否真正执行垃圾收


集,一切都是个未知数。


  (3)挑选适合自己的垃圾收集器。一般来说,如果系统没有特殊和苛刻的性能要求,可以采用JVM的缺省选项。否则可以考虑使用有针对性的垃圾收 集器,比如增量收集器就比较适合实时性要求较高的系统之中。系统具有较高的配置,有比较多的闲置资源,可以考


虑使用并行标记/清除收集器。


  (4)关键的也是难把握的问题是内存泄漏。良好的编程习惯和严谨的编程态度永远是最重要的,不要让自己的一个小错误导致内存出现大漏洞。


  (5)尽早释放无用对象的引用。

 大多数程序员在使用临时变量的时候,都是让引用变量在退出活动域(scope)后,自动设置为null,暗示垃圾收集器来收集该对象,还必须注意该引用的 对象是否被监听,如果有,则要去掉监听器,然后再赋空值。


就是说,对于频繁申请内存和释放内存的操作,还是自己控制一下比较好,但是System.gc()的方法不一定适用,最好使用finallize强 制执行或者写自己的finallize方法。


================================================

tomcat

遇到TOMCAT出错:java.lang.OutOfMemoryError: Java heap space,于是查了资料,找到了解决方法:

If Java runs out of memory, the following error occurs:

 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

 Java heap size can be increased as follows:


java -Xms -Xmx

 Defaults are:

 java -Xms32m -Xmx128m


如果你用win

 /tomcat/bin/catalina.bat 加上下面的命令:

set JAVA_OPTS=-Xms32m -Xmx256m


如果你用unix/linux

 /tomcat/bin/catalina.sh 加上下面的命令:

JAVA_OPTS="-Xms32m -Xmx256m"


 jvm 内存查看与分析工具  


业界有很多强大的java profile的工具,比如Jporfiler,yourkit,这些收费的东西我就不想说了,想说的是,其实java自己就提供了很多内存监控的小工具,下面列举的工具只是一小部分,仔细研究下jdk的工具,还是蛮有意思的呢:) 

    

1:gc日志输出   


       在jvm启动参数中加入 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimestamps -XX:+PrintGCApplicationStopedTime,jvm将会按照这些参数顺序输出gc概要信息,详细信息,gc时间信息,gc造成 的应用暂停时间。如果在刚才的参数后面加入参数 -


Xloggc:文件路径,gc信息将会输出到指定的文件中。其他参数还有 


-verbose:gc和-XX:+PrintTenuringDistribution等。 


2:jconsole  


      jconsole是jdk自带的一个内存分析工具,它提供了图形界面。可以查看到被监控的jvm的内存信息,线程信息,类加载信息,MBean信息。 


      jconsole位于jdk目录下的bin目录,在windows下是jconsole.exe,在unix和linux下是 jconsole.sh,jconsole可以监控本地应用,也可以监控远程应用。 要监控本地应用,执行jconsole pid,pid就是运行的java进程id,如果不带上pid参数,则执行jconsole命


令后,会看到一个对话框弹出,上面列出了本地的java进 程,可以选择一个进行监控。如果要远程监控,则要在远程服务器的jvm参数里加入一些东西,因为jconsole的远程监控基于jmx的,关于 jconsole详细用法,请见专门介绍jconsle的文章,我也会在博客里专门详


细介绍jconsole。 


3:jviusalvm   


      在JDK6 update 7之后,jdk推出了另外一个工具:jvisualvm,java可视化虚拟机,它不但提供了jconsole类似的功能,还提供了jvm内存和cpu实时诊断,还有手动dump出jvm内存情况,手动执行gc。 


     和jconsole一样,运行jviusalvm,在jdk的bin目录下执行jviusalvm,windows下是jviusalvm.exe,linux和unix下是jviusalvm.sh。 


4:jmap   


    jmap是jdk自带的jvm内存分析的工具,位于jdk的bin目录。jdk1.6中jmap命令用法: 


收藏代码

1.Usage:  

2.jmap -histo <pid> (to connect to running process and print histogram of java object heap   

3.jmap -dump:<dump-options> <pid>  (to connect to running process and dump java heap)  

4.dump-options: format=b binary default file=<file>   

5.dump heap to <file>    

6.Example: jmap -dump:format=b,file=heap.bin <pid>   


    jmap -histo <pid>在屏幕上显示出指定pid的jvm内存状况。以我本机为例,执行该命令,屏幕显示: 




收藏代码

1.1:         24206        2791864  < constMethodKlass >    

2.2:         22371        2145216  [C   

3.3:         24206        1940648  < methodKlass >    

4.4:          1951        1364496  < constantPoolKlass >    

5.5:         26543        1282560  < symbolKlass >    

6.6:          6377        1081744  [B   

7.7:          1793         909688  < constantPoolCacheKlass >    

8.8:          1471         614624  < instanceKlassKlass >    

9.9:         14581         548336  [Ljava.lang.Object;   

10.10:          3863         513640  [I   

11.11:         20677         496248  java.lang.String      

12.12:          3621         312776  [Ljava.util.HashMap$Entry;   

13.13:          3335         266800  java.lang.reflect.Method   

14.14:          8256         264192  java.io.ObjectStreamClass$WeakClassKey   

15.15:          7066         226112  java.util.TreeMap$Entry   

16.16:          2355         173304  [S   

17.17:          1687         161952  java.lang.Class   

18.18:          2769         150112  [[I   

19.19:          3563         142520  java.util.HashMap   

20.20:          5562         133488  java.util.HashMap$Entry   

21.Total        239019       17140408   


  为了方便查看,我删掉了一些行。从上面的信息很容易看出,#instance指的是对象数量,#bytes指的是这些对象占用的内存大小,class name指的是对象类型。 


     再看jmap的dump选项,这个选项是将jvm的堆中内存信息输出到一个文件中,在我本机执行 


jmap -dump:file=c:dump.txt 340   


注意340是我本机的java进程pid,dump出来的文件比较 大有10几M,而且我只是开了tomcat,跑了一个很简单的应用,且没有任何访问,可以想象,大型繁忙的服务器上,dump出来的文件该有多大。需要知 道的是,dump出来的文件信息是很原始的,绝不适合人直接观看


,而jmap -histo显示的内容又太简单,例如只显示某些类型的对象占用多大内存,以及这些对象的数量,但是没有更详细的信息,例如这些对象分别是由谁创建的。那 这么说,dump出来的文件有什么用呢?当然有用,因为有专门分析jvm的内存dump文件的工具。 


5:jhat   


    上面说了,有很多工具都能分析jvm的内存dump文件,jhat就是sun jdk6及以上版本自带的工具,位于jdk的bin目录,执行 jhat -J -Xmx512m [file] ,file就是dump文件路径。jhat内置一个简单的web服务器,此命令执行后,jhat在命令行里显示分析结果的访问地


址,可以用 -port选项指定端口,具体用法可以执行jhat -heap查看帮助信息。访问指定地址后,就能看到页面上显示的信息,比jmap -histo命令显示的丰富得多,更为详细。 


6:eclipse内存分析器  


    上面说了jhat,它能分析jvm的dump文件,但是全部是文字显示,eclipse memory analyzer,是一个eclipse提供用于分析jvm 堆dump的插件,网址为 http://www.eclipse.org/mat  ,它的分析速度比jhat快,分析结果是图形界面显示,比jhat的可读性更高。其实


jvisualvm也可以分析dump文件,也是有图形界面显示的。 


7:jstat  


      如果说jmap倾向于分析jvm内存中对象信息的话,那么jsta就是倾向于分析jvm内存的gc情况。都是jvm内存分析工具,但显然,它们是从不同维 度来分析的。jsat常用的参数有很多,如 -gc,-gcutil,-gccause,这些选项具体作用可查看jsat帮助信息,我经常用-


gcutil,这个参数的作用不断的显示当前指定的 jvm内存的垃圾收集的信息。 


      我在本机执行 jstat -gcutil 340 10000,这个命令是每个10秒钟输出一次jvm的gc信息,10000指的是间隔时间为10000毫秒。屏幕上显示如下信息(我只取了第一行,因为是 按的一定频率显示,所以实际执行的时候,会有很多行): 


  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT   

  54.62   0.00  42.87  43.52  86.24   1792    5.093    33    7.670   12.763 


        额。。。怎么说呢,要看懂这些信息代表什么意思,还必须对jvm的gc机制有一定的了解才行啊。其实如果对sun的 hot spot jvm的gc比较了解的人,应该很容易看懂这些信息,但是不清楚gc机制的人,有点莫名其妙,所以在这里我还是先讲讲sun的jvm的gc机制


吧。说到 gc,其实不仅仅只是java的概念,其实在java之前,就有很多语言有gc的概念了,gc嘛就是垃圾收集的意思,更多的是一种算法性的东西,而跟具体 语言没太大关系,所以关于gc的历史,gc的主流算法我就不讲了,那扯得太远了,扯得太远了就是扯淡。sun现


在的jvm,内存的管理模型是分代模型,所 以gc当然是分代收集了。分代是什么意思呢?就是将对象按照生命周期分成三个层次,分别是:新生代,旧生代,持久代。对象刚开始分配的时候,大部分都在新 生代,当新生代gc提交被触发后了,执行一次新生代范围内的gc


,这叫minor gc,如果执行了几次minor gc后,还有对象存活,将这些对象转入旧生代,因为这些对象已经经过了组织的重重考验了哇。旧生代的gc频率会更低一些,如果旧生代执行了gc,那就是 full gc,因为不是局部gc,而是全内存范围的gc,这会造成应用停顿,


因为全内存收集,必须封锁内存,不许有新的对象分配到内存,持久代就是一些jvm期 间,基本不会消失的对象,例如class的定义,jvm方法区信息,例如静态块。需要主要的是,新生代里又分了三个空 间:eden,susvivor0,susvivor1,按字面上来理解,就是伊甸园


区,幸存1区,幸存2区。新对象分配在eden区中,eden区满 时,采用标记-复制算法,即检查出eden区存活 的对象,并将这些对象复制到是s0或s1中,然后清空eden区。jvm的gc说开来,不只是这么简单,例如还有串行收集,并行收集,并发收集,还有著名 的火车算法


,不过那说得太远了,现在对这个有大致了解就好。说到这里,再来看一下上面输出的信息: 


   S0       S1       E        O          P       YGC     YGCT    FGC    FGCT     GCT   

  54.62   0.00  42.87  43.52  86.24   1792    5.093    33    7.670   12.763 


S0:新生代的susvivor0区,空间使用率为54..62% 


S1:新生代的susvivor1区,空间使用率为0.00%(因为还没有执行第二次minor收集) 


E:eden区,空间使用率42.87% 


O:旧生代,空间使用率43.52% 


P:持久带,空间使用率86.24% 


YGC:minor gc执行次数1792次 


YGCT:minor gc耗费的时间5.093毫秒 


FGC:full gc执行次数33 


FGCT:full gc耗费的时间7.670毫秒 


GCT:gc耗费的总时间12.763毫秒 


 怎样选择工具   


     上面列举的一些工具,各有利弊,其实如果在开发环境,使用什么样的工具是无所谓的,只要能得到结果就好。但是在生产环境里,却不能乱选择,因为这些工具本 身就会耗费大量的系统资源,如果在一个生产服务器压力很大的时候,贸然执行这些工具,可能会


造成很意外的情况。最好不要在服务器本机监控,远程监控会比较 好一些,但是如果要远程监控,服务器端的启动脚本要加入一些jvm参数,例如用jconsloe远程监控tomcat或jboss等,都需要设置jvm的 jmx参数,如果仅仅只是分析服务器的内存分配和gc信息,强烈推荐,先用jmap导出服务器端的jvm的堆dump文件,然后再用jhat,或者 jvisualvm,或者eclipse内存分析器来分析内存状况。 

java heap space


标签:

技术支持:企信网 Copyright @ 2011-2023 东莞企信SEO公司 13326882788 版权所有企信网络本站主营东莞网站推广,企信宝SEO建站系统,东莞seo,东莞网络推广,东莞网站优化,东莞网站建设公司  粤ICP备2021042450号

cache
Processed in 0.012286 Second.