本文目录一览:
- java垃圾回收那点事究竟有多少GC
- 如何设置Java虚拟机JVM启动内存参数
- Java的young代、old代以及permanent代,在哪给young代、old代以及perm
- java jvm 的内存到底是什么分配的,看得有点糊涂。
- 如何调整java虚拟机内存大小
- 如何监控java堆内存 virtualmachine
java垃圾回收那点事究竟有多少GC
GC不可怕,可怕的是经常FULL GC,让整个JVM停止工作进行内存回收。 常见的几种触发点如下:
- 持久带满了,就是Permanet Generation满了会导致FULL GC,如果GC不成功,那就报out of memory了。
- 旧生代满了,导致FULL GC。
- 新生代向S0和S1转移数据,S0和S1向旧生代转移数据,结果两边的内存设置都比较小,持续出现,会导致FULL GC。
- 系统直接system.gc。 常见的调整方法就是在server和client模式下调整我们的GC策略来满足特定场合的需要。一般情况下不需要做这方面的特别调优,只需要设置好持久带和新生代(S0,S1,Eden)、旧生代的内存大小即可。Java会自动回收当前的资源,如果有需要就自己调用full gc。 我们把GC分成4种类型:
- SerialGC
参数:-XX:+UseSerialGC
就是Young区和Old区都使用Serial垃圾回收算法。 - ParallelGC
参数:-XX:+UseParallelGC
- Young区:使用Parallel Scavenge回收算法
- Old区:可以使用单线程的或者Parallel垃圾回收算法,由
-XX:+UseParallelOldGC
来控制。
- CMS
参数:-XX:+UseConcMarkSweepGC
- Young区:可以使用普通的或者Parallel垃圾回收算法,由参数
-XX:+UseParNewGC
来控制。 - Old区:只能使用Concurrent Mark Sweep。
- Young区:可以使用普通的或者Parallel垃圾回收算法,由参数
- G1
参数:-XX:+UseG1GC
没有Young/old区。
如何设置Java虚拟机JVM启动内存参数
-Xmx
Java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定。-Xms
Java Heap初始值,Server端JVM最好将-Xms
和-Xmx
设为相同值,开发测试机JVM可以保留默认值。-Xmn
Java Heap Young区大小,不熟悉最好保留默认值。-Xss
每个线程的Stack大小,不熟悉最好保留默认值。
如何设置JVM内存分配:
- 当在命令提示符下启动并使用JVM时(只对当前运行的类Test生效):
java -Xmx128m -Xms64m -Xmn32m -Xss16m Test
- 当在集成开发环境下(如eclipse)启动并使用JVM时:
a. 在eclipse根目录下打开
eclipse.ini
,默认内容为(这里设置的是运行当前开发工具的JVM内存分配)
Java的young代、old代以及permanent代,在哪给young代、old代以及perm
你的这个问题涉及面太广,需要配合图文进行理解,而且JDK4、5、6、7、8标准都不相同,而且不同厂家的JVM实现策略也各不相同。 JVM的优化没有一个固定的配置方法,根据你部署的代码特点配置优化,是一个渐进的工程。
java jvm 的内存到底是什么分配的,看得有点糊涂。
一个完整的Java程序运行过程会涉及以下内存区域:
- 寄存器:JVM内部虚拟寄存器,存取速度非常快,程序不可控制。
- 栈:保存局部变量的值,包括:1. 用来保存基本数据类型的值;2. 保存类的实例,即堆区对象的引用(指针)。也可以用来保存加载方法时的帧。
- 堆:用来存放动态产生的数据,比如new出来的对象。注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。
- 常量池:JVM为每个已加载的类型维护一个常量池,常量池就是这个类型用到的常量的一个有序集合。包括直接常量(基本类型,String)和对其他类型、方法、字段的符号引用。池中的数据和数组一样通过索引访问。由于常量池包含了一个类型所有的对其他类型、方法、字段的符号引用,所以常量池在Java的动态链接中起了核心作用。常量池存在于堆中。
- 代码段:用来存放从硬盘上读取的源程序代码。
- 数据段:用来存放static定义的静态成员。
如何调整java虚拟机内存大小
在一些规模稍大的应用中,Java虚拟机(JVM)的内存设置尤为重要,想在项目中取得好的效率,GC(垃圾回收)的设置是第一步。
- PermGen space:全称是Permanent Generation space。就是说是永久保存的区域,用于存放Class和Meta信息,Class在被Load的时候被放入该区域。
- Heap space:存放Instance。 GC(Garbage Collection)应该不会对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGen space错误。 Java Heap分为3个区:
- Young:保存刚实例化的对象。当该区被填满时,GC会将对象移到Old区。
- Old
- Permanent:负责保存反射对象。
JVM的Heap分配可以使用
-X
参数设定:
-Xms
:初始Heap大小-Xmx
:Java Heap最大值-Xmn
:Young generation的heap大小 JVM有2个GC线程:- 第一个线程负责回收Heap的Young区
- 第二个线程在Heap不足时,遍历Heap,将Young区升级为Older区
Older区的大小等于
-Xmx
减去-Xmn
,不能将-Xms
的值设的过大,因为第二个线程被迫运行会降低JVM的性能。
为什么一些程序频繁发生GC?
有如下原因:
- 程序内调用了
System.gc()
或Runtime.gc()
。 - 一些中间件软件调用自己的GC方法,此时需要设置参数禁止这些GC。
- Java的Heap太小,一般默认的Heap值都很小。
- 频繁实例化对象,Release对象。此时尽量保存并重用对象,例如使用
StringBuffer()
和String()
。 如果你发现每次GC后,Heap的剩余空间会是总空间的50%,这表示你的Heap处于健康状态。许多Server端的Java程序每次GC后最好能有65%的剩余空间。
经验之谈:
- Server端JVM最好将
-Xms
和-Xmx
设为相同值。为了优化GC,最好让-Xmn
值约等于-Xmx
的1/3。 - 一个GUI程序最好是每10到20秒间运行一次GC,每次在半秒之内完成。
注意:
- 增加Heap的大小虽然会降低GC的频率,但也增加了每次GC的时间。并且GC运行时,所有的用户线程将暂停,也就是GC期间,Java应用程序不做任何工作。
- Heap大小并不决定进程的内存使用量。进程的内存使用量要大于
-Xmx
定义的值,因为Java为其他任务分配内存,例如每个线程的Stack等。
Stack的设定
每个线程都有他自己的Stack。
-Xss
:每个线程的Stack大小 Stack的大小限制着线程的数量。如果Stack过大就好导致内存溢漏。-Xss
参数决定Stack大小,例如-Xss1024K
。如果Stack太小,也会导致Stack溢漏。
硬件环境
硬件环境也影响GC的效率,例如机器的种类、内存、swap空间和CPU的数量。 如果你的程序需要频繁创建很多transient对象,会导致JVM频繁GC。这种情况你可以增加机器的内存,来减少Swap空间的使用。
4种GC
- 第一种为单线程GC,也是默认的GC,该GC适用于单CPU机器。
- 第二种为Throughput GC,是多线程的GC,适用于多CPU,使用大量线程的程序。与第一种GC相似,不同在于GC在收集Young区是多线程的,但在Old区和第一种一样,仍然采用单线程。参数:
-XX:+UseParallelGC
。 - 第三种为Concurrent Low Pause GC,类似于第一种,适用于多CPU,并要求缩短因GC造成程序停滞的时间。这种GC可以在Old区的回收同时,运行应用程序。参数:
-XX:+UseConcMarkSweepGC
。 - 第四种为Incremental Low Pause GC,适用于要求缩短因GC造成程序停滞的时间。这种GC可以在Young区回收的同时,回收一部分Old区对象。参数:
-Xincgc
。
单文件的JVM内存进行设置
默认的Java虚拟机的大小比较小,在对大数据进行处理时Java就会报错:java.lang.OutOfMemoryError
。
设置JVM内存的方法,对于单独的.class
,可以用下面的方法对Test运行时的JVM内存进行设置:
java -Xms64m -Xmx256m Test
-Xms
:设置内存初始化的大小-Xmx
:设置最大能够使用内存的大小(最好不要超过物理内存大小)
Tomcat启动JVM内存设置
Linux:
在/usr/local/apache-tomcat-5.5.23/bin
目录下的catalina.sh
添加:
JAVA_OPTS='-Xms512m -Xmx1024m'
Windows:
在catalina.bat
最前面加入:
set JAVA_OPTS=-Xms128m -Xmx350m
如果用startup.bat
启动Tomcat,OK设置生效。但是如果不是执行startup.bat
启动Tomcat而是利用Windows的系统服务启动Tomcat服务,上面的设置就不生效了。解决办法:
修改注册表:
HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Tomcat Service Manager\Tomcat5\Parameters\JavaOptions
原值为:
-Dcatalina.home="C:\ApacheGroup\Tomcat 5.0"
-Djava.endorsed.dirs="C:\ApacheGroup\Tomcat 5.0\common\endorsed"
-Xrs
加入:
-Xms300m -Xmx350m
重启Tomcat服务,设置生效。
Weblogic启动JVM内存设置
在Weblogic中,可以在startweblogic.cmd
中对每个domain虚拟内存的大小进行设置,默认的设置是在commEnv.cmd
里面。
JBoss
默认可以使用的内存为64MB:
$JBOSSDIR$/bin/run.config
JAVA_OPTS = "-server -Xms128 -Xmx512"
Eclipse
在所在目录下,键入:
eclipse.exe -vmargs -Xms256m -Xmx512m
256m表示JVM堆内存最小值,512m表示JVM堆内存最大。
Websphere
进入控制台去设置:应用程序服务器 server1 进程定义 Java 虚拟机。
如何监控java堆内存 virtualmachine
分代收集(Generational Collecting)
基于对对象生命周期分析后得出的垃圾回收算法,把对象分为年轻代、年老代、持久代,对不同生命周期的对象使用不同的算法进行回收。现在的垃圾回收器(从J2SE1.2开始)都是使用此算法。 Sun JVM内存区域分布图:
- Young(年轻代)
Young被划分为三个区间,Eden区和两个大小严格相同的Survivor区,其中Survivor区,在某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用。在Young区间变满的时候,Minor GC就会将存活的对象移到空闲的Survivor区中,根据JVM的策略,在经过几次Minor GC后,任然存活于Survivor区的对象将被移动到Tenured中。 - Tenured(年老代)
Tenured主要保存生命周期长的对象,一般是一些老的对象,当一些对象在Young复制转移一定的次数以后,对象就会被转移到Tenured。一般如果系统中用了application级别的缓存,缓存中的对象往往会被转移到这一区间。 - Perm(持久代)
Perm主要保存class、method、filed等对象,这部分的空间一般不会溢出,除非一次性加载了很多的类。不过在涉及到应用服务器的热部署时,有时候会遇到java.lang.OutOfMemoryError: PermGen space
的错误,造成这个错误的很大原因就有可能是每次热部署后,旧的class没有被卸载掉,这样就造成了大量的class对象保存在了Perm中。这种情况下一般重新启动应用服务器可以解决问题,或者通过-XX:MaxPermSize=N
将持久代大小设大点。
GC类型
大略上分以下2种:
- Minor GC
一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Minor GC在Eden区清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后再整理Survivor的两个区。 - Full GC
对整个堆进行整理,包括Young、Tenured以及Perm。Full GC比Minor GC要慢,因此应该尽可能减少Full GC。以下几种原因可能导致Full GC:- Tenured或Perm被写满
System.gc
被显示调用- 上一次GC后堆空间分配策略动态调整
JVM调优参数
JVM提供了相应的参数来对内存大小、垃圾回收算法进行配置。
Non-standard Java HotSpot VM Options
我在32位Windows Server 2003系统8GB物理内存,JDK1.6下测试,最大可设置为1536M,再多JVM就跑不起来了。
-Xms1536M
:设置JVM启动后堆的初始内存(这里配置的JVM堆空间只是Young与Tenured)-Xmx1536M
:设置JVM启动后堆的最大内存,一般在生产环境中把这两个参数设为相同值,避免在“上一次GC后堆空间分配策略动态调整”而引起Full GC-Xss1M
:设置每个线程的Java栈大小-XX:NewRatio=2
:设置Tenured和Young的比值为2:1,这样Eden+2*Survivor=1/3堆内存-XX:SurvivorRatio=8
:设置Eden和一个Survivor的比值为8:1,这样一个Survivor就占Young区的1/10-XX:PermSize=64M
:设置持久代初始内存-XX:MaxPermSize=128M
:设置持久代最大内存
垃圾收集器
JVM给了三种选择:串行收集器、并行收集器、并发收集器。串行收集器对于处理大数据量的情况时性能太低,所以一般选择使用并行收集器和并发收集器。J2SE5.0以后JVM会根据当前系统配置进行判断(机器配置只要有2个CPU和至少2GB的物理内存JVM将自动以-server模式运行)
- 吞吐量优先的并行收集器,通过
-XX:+UseParallelGC
指定 - 响应时间优先的并发收集器,主要是保证系统的响应时间,减少垃圾收集时的停顿时间。通过
-XX:+UseConcMarkSweepGC
指定。由于CMS GC是和应用并发执行的,因此需要耗费更多的CPU资源。
Sun JDK自带的图形监控和管理工具jconsole
通过Sun JDK自带的一个图形监控和管理工具jconsole能很容易的看到当前虚拟机中的内存状态,我使用的JDK版本是jdk1.6.0_18,这个工具从jdk1.5就有了。