浅谈JAVA虚拟机(JVM)1.概念:.JVM(JavaVirtualMachine):Java虚拟机,所有的Java程序都在Java虚拟机中运行。元数据:在本文中指用于描述类和接口定义的数据。2.遇到的问题在我做J2EE系统开发的工作生涯中,经常遇到技术人员或客户发出诸如此类的感慨:我的J2EE应用系统处理的数据量不大,系统体积也不大,技术架构也没有问题,我的应用服务器的内存有4G或8G;系统运行起来很慢,还经常出现内存溢出错误。真是无奈!每次遇到这样的情况,我心中都会忍不住窃笑之。其实他们所遇到这种情况,不是技术架构上的问题,不是系统本身的问题,也不是应用服务器的问题,也可能不是服务器的内存资源真的不足的问题。他们花了很多时间在J2EE应用系统本身上找问题(当然一般情况下,这种做法是对的;当出现问题时,在自身上多找找有什么不足),结果还是解决不了问题。他们却忽略了很重要的一点:J2EE应用系统是运行在J2EE应用服务器上的,而J2EE应用服务器又是运行在JVM(JavaVirtualMachine)上的。3.不止一个JVM其实在生产环境中JVM参数的优化和设置对J2EE应用系统性能有着决定性的作用。本篇我们就来分析JAVA的创建者SUN公司的JVM的内存管理机制(在现实中绝大多数的应用服务器是运行在SUN公司的JVM上的,当然除了SUN公司的JVM,还有IBM的JVM,Bean的JVM等)。4.JVM的内存管理机制JVM的早期版本并没有进行分区管理;这样的后果是JVM进行垃圾回收时,不得不扫描JVM所管理的整片内存,所以搜集垃圾是很耗费资源的事情,也是早期JAVA程序的性能低下的主要原因。随着JVM的发展,JVM引进了分区管理的机制。采用分区管理机制的JVM将JVM所管理的所有内存资源分为2个大的部分。永久存储区(PermanentSpace)和堆空间(TheHeapSpace)。其中堆空间又分为新生区(Young(New)generationspace)和养老区(Tenure(Old)generationspace),新生区又分为伊甸园(Edenspace),幸存者0区(Survivor0space)和幸存者1区(Survivor1space)。具体分区如下图:4.1JVM分区的用途永久存储区(PermanentSpace):永久存储区是JVM的驻留内存,用于存放JDK自身所携带的Class,Interface的元数据,应用服务器允许必须的Class,Interface的元数据和Java程序运行时需要的Class和Interface的元数据。被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭JVM时,释放此区域所控制的内存。堆空间(TheHeapSpace):是JAVA对象生死存亡的地区,JAVA对象的出生,成长,死亡都在这个区域完成。堆空间又分别按JAVA对象的创建和年龄特征分为养老区和新生区。新生区(Young(New)generationspace):新生区的作用包括JAVA对象的创建和从JAVA对象中筛选出能进入养老区的JAVA对象。伊甸园(Edenspace):JAVA对空间中的所有对象在此出生,该区的名字因此而得名。也即是说当你的JAVA程序运行时,需要创建新的对象,JVM将在该区为你创建一个指定的对象供程序使用。创建对象的依据即是永久存储区中的元数据。幸存者0区(Survivor0space)和幸存者1区(Survivor1space):当伊甸园的控件用完时,程序又需要创建对象;此时JVM的垃圾回收器将对伊甸园区进行垃圾回收,将伊甸园区中的不再被其他对象所引用的对象进行销毁工作。同时将伊甸园中的还有其他对象引用的对象移动到幸存者0区。幸存者0区就是用于存放伊甸园垃圾回收时所幸存下来的JAVA对象。当将伊甸园中的还有其他对象引用的对象移动到幸存者0区时,如果幸存者0区也没有空间来存放这些对象时,JVM的垃圾回收器将对幸存者0区进行垃圾回收处理,将幸存者0区中不在有其他对象引用的JAVA对象进行销毁,将幸存者0区中还有其他对象引用的对象移动到幸存者1区。幸存者1区的作用就是用于存放幸存者0区垃圾回收处理所幸存下来的JAVA对象。养老区(Tenure(Old)generationspace):用于保存从新生区筛选出来的JAVA对象。4.2JVM的垃圾回收工作如何运作首先当启动J2EE应用服务器时,JVM随之启动,并将JDK的类和接口,应用服务器运行时需要的类和接口以及J2EE应用的类和接口定义文件也及编译后的Class文件或JAR包中的Class文件装载到JVM的永久存储区。在伊甸园中创建JVM,应用服务器运行时必须的JAVA对象,创建J2EE应用启动时必须创建的JAVA对象;J2EE应用启动完毕,可对外提供服务。JVM在伊甸园区根据用户的每次请求创建相应的JAVA对象,当伊甸园的空间不足以用来创建新JAVA对象的时候,JVM的垃圾回收器执行对伊甸园区的垃圾回收工作,销毁那些不再被其他对象引用的JAVA对象(如果该对象仅仅被一个没有其他对象引用的对象引用的话,此对象也被归为没有存在的必要,依此类推),并将那些被其他对象所引用的JAVA对象移动到幸存者0区。如果幸存者0区有足够控件存放则直接放到幸存者0区;如果幸存者0区没有足够空间存放,则JVM的垃圾回收器执行对幸存者0区的垃圾回收工作,销毁那些不再被其他对象引用的JAVA对象(如果该对象仅仅被一个没有其他对象引用的对象引用的话,此对象也被归为没有存在的必要,依此类推),并将那些被其他对象所引用的JAVA对象移动到幸存者1区。如果幸存者1区有足够控件存放则直接放到幸存者1区;如果幸存者0区没有足够空间存放,则JVM的垃圾回收器执行对幸存者0区的垃圾回收工作,销毁那些不再被其他对象引用的JAVA对象(如果该对象仅仅被一个没有其他对象引用的对象引用的话,此对象也被归为没有存在的必要,依此类推),并将那些被其他对象所引用的JAVA对象移动到养老区。如果养老区有足够控件存放则直接放到养老区;如果养老区没有足够空间存放,则JVM的垃圾回收器执行对养老区区的垃圾回收工作,销毁那些不再被其他对象引用的JAVA对象(如果该对象仅仅被一个没有其他对象引用的对象引用的话,此对象也被归为没有存在的必要,依此类推),并保留那些被其他对象所引用的JAVA对象。如果到最后养老区,幸存者1区,幸存者0区和伊甸园区都没有空间的话,则JVM会报告“JVM堆空间溢出(java.lang.OutOfMemoryError:Javaheapspace)”,也即是在堆空间没有空间来创建对象。这就是JVM的内存分区管理,相比不分区来说;一般情况下,垃圾回收的速度要快很多;因为在没有必要的时候不用扫描整片内存而节省了大量时间。通常大家还会遇到另外一种内存溢出错误“永久存储区溢出(java.lang.OutOfMemoryError:JavaPermanentSpace)”。5.Java虚拟机(JVM)中的内存设置详解在一些规模稍大的应用中,Java虚拟机(JVM)的内存设置尤为重要,想在项目中取得好的效率,GC(垃圾回收)的设置是第一步。PermGenspace:全称是PermanentGenerationspace.就是说是永久保存的区域,用于存放Class和Meta信息,Class在被Load的时候被放入该区域Heapspace:存放Instance。GC(GarbageCollection)应该不会对PermGenspace进行清理,所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGenspace错误JavaHeap分为3个区1.Young2.Old3.PermanentYoung保存刚实例化的对象。当该区被填满时,GC会将对象移到Old区。Permanent区则负责保存反射对象,本文不讨论该区。JVM的Heap分配可以使用-X参数设定,-Xms初始Heap大小-Xmxjavaheap最大值-Xmnyounggeneration的heap大小JVM有2个GC线程第一个线程负责回收Heap的Young区第二个线程在Heap不足时,遍历Heap,将Young区升级为Older区Older区的大小等于-Xmx减去-Xmn,不能将-Xms的值设的过大,因为第二个线程被迫运行会降低JVM的性能。为什么一些程序频繁发生GC?有如下原因:1.程序内调用了System.gc()或Runtime.gc()。2.一些中间件软件调用自己的GC方法,此时需要设置参数禁止这些GC。3.Java的Heap太小,一般默认的Heap值都很小。4.频繁实例化对象,Release对象此时尽量保存并重用对象,例如使用StringBuffer()和String()。如果你发现每次GC后,Heap的剩余空间会是总空间的50%,这表示你的Heap处于健康状态,许多Server端的Java程序每次GC后最好能有65%的剩余空间经验之谈:1.Server端JVM最好将-Xms和-Xmx设为相同值。为了优化GC,最好让-Xmn值约等于-Xmx的1/3。2.一个GUI程序最好是每10到20秒间运行一次GC,每次在半秒之内完成。注意:1.增加Heap的大小虽然会降低GC的频率,但也增加了每次GC的时间。并且GC运行时,所有的用户线程将暂停,也就是GC期间,Java应用程序不做任何工作。2.Heap大小并不决定进程的内存使用量。进程的内存使用量要大于-Xmx定义的值,因为Java为其他任务分配内存,例如每个线程的Stack等。Stack的设定每个线程都有他自己的Stack。-Xss每个线程的Stack大小Stack的大小限制着线程的数量。如果Stack过大就好导致内存溢漏。-Xss参数决定Stack大小,例如-Xss1024K。如果Stack太小,也会导致Stack溢漏。硬件环境硬件环境也影响GC的效率,例如机器的种类,内存,swap空间,和CPU的数量。如果你的程序需要频繁创建很多transient对象,会导致JVM频繁GC。这种情况你可以增加机器的内存,来减少Swap空间的使用。4种GC1、第一种为单线程GC,也是默认的GC,该GC适用于单CPU机器。2、第二种为ThroughputGC,是多线程的GC,适用于多CPU,使用大量线程的程序。第二种GC与第一种GC相似,不同在于GC在收集Young区是多线程的,但在Old区和第一种一样,仍然采用单线程。-XX:+UseParallelGC参数启动该GC。3、第三种为ConcurrentLowPauseGC,类似于第一种,适用于多CPU,并要求缩短因GC造成程序停滞的时间。这种GC可以在Old区的回收同时,运行应用程序。-XX:+UseConcMarkSweepGC参数启动该GC。4、第四种为IncrementalLowPauseGC,适用于要求缩短因GC造成程序停滞的时间。这种GC可以在Young区回收的同时,回收一部分Old区对象。-Xincgc参数启动该GC。单文件的JVM内存进行设置默认的java虚拟机的大小比较小,在对大数据进行处理时java就会报错:java.lang.OutOfMemoryError。设置jvm内存的方法,对于单独的.class,可以用下面的方法对Test运行时的jvm内存进行设置。java-Xms64m-Xmx256mTest-Xms是设置内存初始化的大小-Xmx是设置最大能够使用内存的大小(最好不要超过物理内存大小)tomcat启动jvm内存设置Linux:在/usr/local/apache-tomcat-5.5.23/bin目录下的catalina.sh添加:JAVA_OPTS='-Xms512m-Xmx1024m'要加“m”说明是MB,否则就是KB了,在启动tomcat时会报内存不足。-Xms:初始值-Xmx:最大值-Xmn:最小值Windows在catalina.bat最前面加入setJAVA_OPTS=-Xms128m-Xmx