当前位置:文档之家› JVM内存参数详解以及配置调优

JVM内存参数详解以及配置调优

JVM内存参数详解以及配置调优
JVM内存参数详解以及配置调优

JVM的结构

从功能上分,Java虚拟机主要由六个部分组成,可以分成三类:

第一类:JVM API:就是我们最常用的Java API,它是开发人员和Java交互的入口,它主要是JAVA_HOME/jre/lib下的运行时类库rt.jar和编译相关的tools.jar

第二类:JVM内部组件

类装载器(ClassLoader):将Byte Array的.class文件装载、链接和初始化。

内存管理(Memory Managent):为对象分配内存,以及释放内存。后者就是垃圾回收Garbage Collector(GC)。由于JVM最复杂的、最影响性能的就是GC,所以内存管理一般就指垃圾回收。

诊断接口(Diagostics Interface):这主要体现在JVMTI(jdk1.4下的JVMPI和JVMDI),它主要用来诊断程序的问题和性能,一般提供给工具厂商实现。如eclispe IDE下的debug功能,Jprofiler 性能调优工具。

类解释器(Interpreter):解释装载进虚拟机的class对象,包括JIT等特性相关。

第三类:平台相关接口(Platform Interface):主要为了跨操作系统平台重用JVM代码,不过,它和我们开发人员关系不大。

在以上六个组件中,我们开发人员最关心的是ClassLoader和GC,用Java做系统框架、容器和它们密切相关。做业务系统时一些基础代码也和它们打交道,譬如最常用的Class.forName(),Thread.currentThread.getContextClassLoader()。我们仔细想想,为什么是上面两个问题?因为,它和我们class的整个生命周期最为相关:怎么将一个class和相关class 加载进来,class实例什么时候创建,什么时候被销毁?

所以,下面的部分我们要专门讨论这些问题。

在JVM中有两种垃圾方式,一种叫做Minor(次收集),另一种叫做Major(主收集)。其中Minor在Young Generation的空间被对象全部占用后执行,主要是对Young Generation中的对象进行垃圾收集。而Major是针对于整个Heap size的垃圾收集。其中Minor方式的收集经常发生,并且Minor收集所占用的系统时间小。Major方式的垃圾收集则是一种“昂贵”的垃圾收集方式,因为在Major要对整个Heap size进行垃圾收集,这会使得应用停顿的时间变得较长。

java -jar -server -verbose:gc -XX:+UseParNewGC -Xmn8m -Xms32m -Xmx32m SwingSet2.jar

使用了-XX:+UseParNewGC选项的minor收集的时间要比不使用的时候优。

java -jar -verbose:gc -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -Xmn64m -Xms256m -Xmx 256m SwingSet2.jar

采用-XX:+UseConcMarkSweepGC选项在Heap Size 比较大而且Major收集时间较长的情况下使用更合适

?堆(Heap)和非堆(Non-heap)内存

按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM 中堆之外的内存称为非堆内存(Non-heap memory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。

?堆内存分配

JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70% 时,JVM会减少堆直到-Xms 的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。

?非堆内存分配

JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。

?JVM内存限制(最大值)

首先JVM内存限制于实际的最大物理内存(废话!呵呵),假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit 以上的处理器就不会有限制了。

jvm的调整没什么技巧,只有一些原则,要根据自己应用的特点来设定调优的目标,这里收集了一些内容,权当记录

Java heap (Xmx, Xms) 和java进程的heap是两回事情

java进程的heap包含:

Java Heap

Permanent Generation

Thread stacks

Native code

Directly allocated memory

Code generation

Garbage collection

TCP buffers

因此我们在设置,jvm参数的时候得小心一点,一般我们会设置java heap 和perm gen,结合操作系统内存的大小和应用特点,选取一个合理的值。

-Xms/-Xmx

java heap并不是越大越好,对他的一般优化原则是够用的情况下,尽可能的小,因为太大的话会浪费内存,同时影响GC的效率

-XX:NewSize/-XX:NewRatio

一般设置为java heap的25%-33%,太大或者太小都会影响GC,要根据应用的特点,对象生命长短周期的比例来调整

GC相关调整的目标:

*短生命周期的对象不要进入Old区

*短生命周期的对象在minor GC的时候干掉

*长生命周期的对象要放到Old区

*长生命周期的对象可以被Full GC清理掉,但是Full GC要调整到尽量少发生

不管采用什么算法,GC总是会导致应用暂停的,这个时间长短从毫秒到秒之间不等,因此会影响应用的相应时间,多长的停顿在接受范围内取决于应用的特征,可以通过设置GC停顿的时间来调整(注意只是期望的时间,而不是绝对)

-XX:MaxGCPauseMillis -XX:MaxGCMinorPauseMillis ,一般设置比较短的停顿时间会导致相对较频繁的GC,根据应用的情况来调整

Xms: java heap初始化时的大小。默认情况是机器物理内存的1/64。这个主要是根据应用启动时消耗的资源决定,分配少了申请起来会降低启动速度,分配多了也浪费。

Xmx:java heap的最大值,默认是机器物理内存的1/4,最大也就到1G。这个值决定了最多可用的Java Heap Memory,分配过少就会在应用需要大量内存作缓存或者零时对象时出现OOM的问题,如果分配过大,那么就会产生上文提到的第二类OOM。所以如何配置还是根据运行过程中的分析和计算来确定,如果不能确定还是采用默认的配置。

Xmn:java heap新生代的空间大小。在GC模型中,根据对象的生命周期的长短,产生了内存分代的设计:青年代(内部也分成三部分,类似于整体划分的作用,可以通过配置来设置比例),老年代,持久代。每一代的管理和回收策略都不相同,最为活跃的就是青年代,同时这部分的内存分配和管理效率也是最高。通常情况下,对于内存的申请优先在新生代中申请,当内存不够时会整理新生代,当整理以后还是不能满足申请的内存,就会向老年代移动一些生命周期较长的对象。这种整理和移动会消耗资源,同时降低系统运行响应能力,因此如果青年代设置的过小,就会频繁的整理和移动,对性能造成影响。那是否把年青代设

置的越大越好,其实不然,年青代采用的是复制搜集算法,这种算法必须停止所有应用程序线程,服务器线程切换时间就会成为应用响应的瓶颈(当然永远不用收集那么就不存在这个问题)。老年代采用的是串行标记收集的方式,并发收集可以减少对于应用的影响。

Xss:线程堆栈最大值。允许更多的虚拟内存空间地址被Java Heap使用。

以下是sun公司的性能优化白皮书中提到的几个例子:

1.对于吞吐量的调优。机器配置:4G的内存,32个线程并发能力。

java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC

-XX:ParallelGCThreads=20

-Xmx3800m -Xms3800m 配置了最大Java Heap来充分利用系统内存。

-Xmn2g 创建足够大的青年代(可以并行被回收)充分利用系统内存,防止将短期对象复制到老年代。

-Xss128 减少默认最大的线程栈大小,提供更多的处理虚拟内存地址空间被进程使用。

-XX:+UseParallelGC 采用并行垃圾收集器对年青代的内存进行收集,提高效率。

-XX:ParallelGCThreads=20 减少垃圾收集线程,默认是和服务器可支持的线程最大并发数相同,往往不需要配置到最大值。

2.尝试采用对老年代并行收集

java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC

-XX:ParallelGCThreads=20 -XX:+UseParallelOldGC

-Xmx3550m -Xms3550m 内存分配被减小,因为ParallelOldGC会增加对于Native Heap的需求,因此需要减小Java Heap来满足需求。

-XX:+UseParallelOldGC 采用对于老年代并发收集的策略,可以提高收集效率。3.提高吞吐量,减少应用停顿时间

java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20

-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:SurvivorRatio=8

-XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=31

-XX:+UseConcMarkSweepGC -XX:+UseParNewGC

选择了并发标记交换收集器,它可以并发执行收集操作,降低应用停止时间,同时它也是并行处理模式,可以有效地利用多处理器的系统的多进程处理。

-XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=31 表示在青年代中Eden和Survivor比例,设置增加了Survivor的大小,越大的survivor空间可以允许短期对象尽量在年青代消亡。

-XX:TargetSurvivorRatio=90 允许90%的空间被占用,超过默认的50%,提高对于survivor的使用率。

基本概念:

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,Old和Permanent。Young保存刚实例化的对象。当该区被填满时,GC 会将对象移到Old区。Permanent区则负责保存反射对象。

1. Heap设定与垃圾回收Java Heap分为3个区,Young,Old和Permanent。Young保存刚实例化的对象。当该区被填满时,GC会将对象移到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

1、第一种为单线程GC,也是默认的GC。,该GC适用于单CPU机器。

2、第二种为Throughput GC,是多线程的GC,适用于多CPU,使用大量线程的程序。第二种GC与第一种GC相似,不同在于GC在收集Young区是多线程的,但在Old区和第一种一样,仍然采用单线程。

-XX:+UseParallelGC参数启动该GC。

3、第三种为Concurrent Low Pause GC,类似于第一种,适用于多CPU,并要求缩短因GC造成程序停滞的时间。这种GC可以在Old区的回收同时,运行应用程序。-XX:+UseConcMarkSweepGC参数启动该GC。

4、第四种为Incremental Low Pause GC,适用于要求缩短因GC造成程序停滞的时间。这种GC可以在Young区回收的同时,回收一部分Old区对象。-Xincgc参数启动该GC。

JVM参数配置

1: heap size

a: -Xmx

指定jvm 的最大heap 大小, 如:-Xmx=2g

b: -Xms

指定jvm 的最小heap 大小, 如:-Xms=2g ,高并发应用,建议和-Xmx一样,防止因为内存收缩/突然增大带来的性能影响。

c: -Xmn

指定jvm 中New Generation 的大小, 如:-Xmn256m。这个参数很影响性能,如果你的程序需要比较多的临时内存,建议设置到512M,如果用的少,尽量降低这个数值,一般来说128/256足以使用了。

d: -XX:PermSize=

指定jvm 中Perm Generation 的最小值, 如:-XX:PermSize=32m。这个参数需要看你的实际情况,。可以通过jmap 命令看看到底需要多少。

e: -XX:MaxPermSize=

指定Perm Generation 的最大值, 如:-XX:MaxPermSize=64m

f: -Xss

指定线程桟大小, 如:-Xss128k,一般来说,webx框架下的应用需要256K。如果你的程序有大规模的递归行为,请考虑设置到512K/1M。这个需要全面的测试才能知道。不过,256K已经很大了。这个参数对性能的影响比较大的。

g: -XX:NewRatio=

指定jvm 中Old Generation heap size 与New Generation 的比例, 在使用CMS GC 的情况下此参

数失效, 如:-XX:NewRatio=2

h: -XX:SurvivorRatio=

指定New Generation 中Eden Space 与一个Survivor Space 的heap size 比

例,-XX:SurvivorRatio=8, 那么在总共New Generation 为10m 的情况下,Eden Space 为8m

i: -XX:MinHeapFreeRatio=

指定jvm heap 在使用率小于n 的情况下,heap 进行收缩,Xmx==Xms 的情况下无效,

如:-XX:MinHeapFreeRatio=30

j: -XX:MaxHeapFreeRatio=

指定jvm heap 在使用率大于n 的情况下,heap 进行扩张,Xmx==Xms 的情况下无效,

如:-XX:MaxHeapFreeRatio=70

k: -XX:LargePageSizeInBytes=

指定Java heap 的分页页面大小, 如:-XX:LargePageSizeInBytes=128m

2: garbage collector

a: -XX:+UseParallelGC

指定在New Generation 使用parallel collector, 并行收集, 暂停app threads, 同时启动多个垃圾回收thread, 不能和CMS gc 一起使用 . 系统吨吐量优先, 但是会有较长长时间的app pause, 后台系统任务可以使用此gc

b: -XX:ParallelGCThreads=

指定parallel collection 时启动的thread 个数, 默认是物理processor 的个数,

c: -XX:+UseParallelOldGC

指定在Old Generation 使用parallel collector

d: -XX:+UseParNewGC

指定在New Generation 使用parallel collector, 是UseParallelGC 的gc 的升级版本, 有更好的性能或者优点, 可以和CMS gc 一起使用

e: -XX:+CMSParallelRemarkEnabled

在使用UseParNewGC 的情况下, 尽量减少mark 的时间

f: -XX:+UseConcMarkSweepGC

指定在Old Generation 使用concurrent cmark sweep gc,gc thread 和app thread 并行( 在

init-mark 和remark 时pause app thread). app pause 时间较短, 适合交互性强的系统, 如web server

g: -XX:+UseCMSCompactAtFullCollection

在使用concurrent gc 的情况下, 防止memory fragmention, 对live object 进行整理, 使memory 碎片减少

h: -XX:CMSInitiatingOccupancyFraction=

指示在old generation 在使用了n% 的比例后, 启动concurrent collector, 默认值是68,

如:-XX:CMSInitiatingOccupancyFraction=70

i: -XX:+UseCMSInitiatingOccupancyOnly

指示只有在old generation 在使用了初始化的比例后concurrent collector 启动收集

3:others

a: -XX:MaxTenuringThreshold=

指定一个object 在经历了n 次young gc 后转移到old generation 区, 在linux64 的java6 下默认值是15, 此参数对于throughput collector 无效, 如:-XX:MaxTenuringThreshold=31

b: -XX:+DisableExplicitGC

禁止java 程序中的full gc, 如System.gc() 的调用. 最好加上么,防止程序在代码里误用了。对性能造成冲击。

c: -XX:+UseFastAccessorMethods

get,set 方法转成本地代码

d: -XX:+PrintGCDetails

打应垃圾收集的情况如:

[GC 15610.466: [ParNew: 229689K->20221K(235968K), 0.0194460 secs]

1159829K->953935K(2070976K), 0.0196420 secs]

e: -XX:+PrintGCTimeStamps

打应垃圾收集的时间情况, 如:

[Times: user=0.09 sys=0.00, real=0.02 secs]

f: -XX:+PrintGCApplicationStoppedTime

打应垃圾收集时, 系统的停顿时间, 如:

Total time for which application threads were stopped: 0.0225920 seconds

JVM内存的调优

1. Heap设定与垃圾回收Java Heap分为3个区,Young,Old和Permanent。Young 保存刚实例化的对象。当该区被填满时,GC会将对象移到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的性能。

Tomcat配置

问题分析:

由于TOMCAT内存溢出而引发的问题,主要原因是JVM的虚拟内存默认为128M,当超过这个值时就把先前占用的内存释放,而导致好象TCP/IP丢包的假象,出现HTTP500的错误。解决方法主要是加大TOMCAT可利用内存,并在程序当中加大内存使用。

解决方法:

Linux下修改JVM内存大小:

要添加在tomcat 的bin 下catalina.sh 里,位置cygwin=false前。注意引号要带上,红色的为新添加的.

# OS specific support. $var _must_ be set to either true or false. JAVA_OPTS="-Xms256m -Xmx512m -Xss1024K -XX:PermSize=128m

-XX:MaxPermSize=256m"

cygwin=false

此时执行 ps -ef|grep tomcat 可以看到tomcat的参数中添加了上面的参数

也可以在/etc/profile文件中添加

export JAVA_OPTS="-Xms256m -Xmx512m -Xss1024K -XX:PermSize=128m

-XX:MaxPermSize=256m"

然后 source /etc/profile

windows下修改JVM内存大小:

情况一:解压版本的Tomcat, 要通过startup.bat启动tomcat才能加载配置

要添加在tomcat 的bin 下catalina.bat 里

rem Guess CATALINA_HOME if not defined

set CURRENT_DIR=%cd%后面添加,红色的为新添加的.

set JAVA_OPTS=-Xms256m -Xmx512m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m -Djava.awt.headless=true

情况二:安装版的Tomcat下没有catalina.bat

windows服务执行的是bin\tomcat.exe.他读取注册表中的值,而不是catalina.bat的设置.

修改注册表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配置:

由于WebLogic的配置问题,我们的测试出现了失败情况。原因是为WebLogic 分配的内存太少了。通过修改commom\bin\commEnv.cmd文件来增加内存分配。

修改的部分如下:

:bea

if "%PRODUCTION_MODE%" == "true" goto bea_prod_mode

set JAVA_VM=-jrockit

set MEM_ARGS=-Xms768m -Xmx1024m

set JAVA_OPTIONS=%JAVA_OPTIONS% -Xverify:none

goto continue

:bea_prod_mode

set JAVA_VM=-jrockit

set MEM_ARGS=-Xms768m -Xmx1024m//原来是128M~256M,太小了,数据太大

goto continue

结果修改后,没有效果。还是有失败的情况。

发现,原来,在:bea下面还有一段配置信息如下:

:sun

if "%PRODUCTION_MODE%" == "true" goto sun_prod_mode

set JAVA_VM=-client

set MEM_ARGS=-Xms768m -Xmx1024m -XX:MaxPermSize=256m

set JAVA_OPTIONS=%JAVA_OPTIONS% -Xverify:none

goto continue

:sun_prod_mode

set JAVA_VM=-server

set MEM_ARGS=-Xms768m -Xmx1024m -XX:MaxPermSize=256m

goto continue

将这里的内存分配修改后见效。

原因是,上面对第一段代码是为bea自己的JVM设置的,下面的是为Sun的设置的。而WebLogic默认的是Sun的,所以出了毛病。在JDK的选择上,weblogic 有两种JDK供选择,一种是Sun的JDK,另外一种是Bea的jrockit。按照bea 的网站的说明,sun jdk提供更好的兼容性,而使用jrockit可以提供更好的性能。作为weblogic集群我全部采用jrockit作为JDK环境,以达到更高的性能。

在默认启动情况下,jrockit启动时为其窗口配置的内存大小比较小。注意weblogic的启动内存配置-Xms32m -Xmx256m,通过修改commEnv.sh可以修改这个参数,Xms表示启动开始分配的内存,Xmx表示最大能分配的内存,这里我们根据应用情况调整为-Xms1536m -Xmx1536m,这点需要根据自身测试情况和系统配置进行调整,经过周一晚的调试,我们目前应用比较合理的窗口内存大小为1536M(2G× 75%),通过top可以观察到测试中的内存反应,最合理的应该是恰好把物理内存用完。

也可以在、/etc/profile中设置:

USER_MEM_ARGS=-server -Xms2048M -Xmx2048M -XX:PermSize=256M

-XX:MaxPermSize=256M -XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=8

查到setDomianEnv.sh里面有一段

# IF USER_MEM_ARGS the environment variable is set, use it to override ALL MEM_ARGS values if [ "${USER_MEM_ARGS}" != "" ] ; then

MEM_ARGS="${USER_MEM_ARGS}"

export MEM_ARGS

fi

意思就是设置了这个参数就会覆盖所有MEM_ARGS初始值吧。

jstat工具特别强大,有众多的可选项,详细查看堆内各个部分的使用量,以及加载类的数量。使用时,需加上查看进程的进程id,和所选参数。以下详细介绍各个参数的意义。

jstat -class pid:显示加载class的数量,及所占空间等信息。

jstat -compiler pid:显示VM实时编译的数量等信息。

jstat -gc pid:可以显示gc的信息,查看gc的次数,及时间。其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。

jstat -gccapacity:可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小,如:PGCMN显示的是最小perm的内存使用量,PGCMX显示的是perm 的内存最大使用量,PGC是当前新生成的perm内存占用量,PC是但前perm内存占用量。其他的可以根据这个类推, OC是old内纯的占用量。

jstat -gcnew pid:new对象的信息。

jstat -gcnewcapacity pid:new对象的信息及其占用量。

jstat -gcold pid:old对象的信息。

jstat -gcoldcapacity pid:old对象的信息及其占用量。

jstat -gcpermcapacity pid: perm对象的信息及其占用量。

jstat -util pid:统计gc信息统计。

jstat -printcompilation pid:当前VM执行的信息。

除了以上一个参数外,还可以同时加上两个数字,如:jstat -printcompilation 3024 250 6是每250毫秒打印一次,一共打印6次,还可以加上-h3每三行显示一下标题。

jmap是一个可以输出所有内存中对象的工具,甚至可以将VM 中的heap,以二进制输出成文本。使用方法 jmap -histo pid。如果连用SHELL jmap -histo pid>a.log可以将其保存到文本中去,在一段时间后,使用文本对比工具,可以对比出GC回收了哪些对象。jmap -dump:format=b,file=String 3024可以将3024进程的内存heap输出出来到String文件里。

jinfo:的用处比较简单,就是能输出并修改运行时的java进程的运行参数。用法是jinfo -opt pid 如:查看2788的MaxPerm大小可以用 jinfo -flag MaxPermSize 2788。

jps:查看当前运行的jvm进程号

jstack:打印当前某个jvm的详细的线程堆栈信息

jstat -gc

S0C Current survivor space 0 capacity (KB). 当前survivor0的容量S1C Current survivor space 1 capacity (KB). 当前survivor1的容量S0U Survivor space 0 utilization (KB). survivor0的使用

S1U Survivor space 1 utilization (KB). survivor1的使用

EC Current eden space capacity (KB). 当前eden的容量

EU Eden space utilization (KB). eden的使用

OC Current old space capacity (KB). 当前old的容量

OU Old space utilization (KB). old的使用

PC Current permanent space capacity (KB). 当前perm的容量PU Permanent space utilization (KB). perm的使用YGC Number of young generation GC Events. young gc的次数YGCT Young generation garbage collection time. young gc的总时间FGC Number of full GC events. full gc的次数

FGCT Full garbage collection time. full gc的总时间

GCT Total garbage collection time. 所有gc的总时间

Java虚拟机(JVM)参数配置说明

Java虚拟机(JVM)参数配置说明 在Java、J2EE大型应用中,JVM非标准参数的配置直接关系到整个系统的性能。 JVM非标准参数指的是JVM底层的一些配置参数,这些参数在一般开发中默认即可,不需要任何配置。但是在生产环境中,为了提高性能,往往需要调整这些参数,以求系统达到最佳新能。另外这些参数的配置也是影响系统稳定性的一个重要因素,相信大多数Java开发人员都见过“O utOfMem ory”类型的错误。呵呵,这其中很可能就是JVM参数配置不当或者就没有配置没意识到配置引起的。 为了说明这些参数,还需要说说JDK中的命令行工具一些知识做铺垫。 首先看如何获取这些命令配置信息说明: 假设你是windows平台,你安装了J2SDK,那么现在你从cmd控制台窗口进入J2SDK安装目录下的bin目录,然后运行java命令,出现如下结果,这些就是包括java.exe工具的和J VM的所有命令都在里面。 ----------------------------------------------------------------------- D:\j2sdk15\bin>java Usage: java [-options] class [args...] (to execute a class) or java [-options] -jar jarfile [args...] (to execute a jar file) where options include: -client to select the "client" VM -server to select the "server" VM -hotspot is a synonym for the "client" VM [deprecated] The default VM is client.

JVM调优总结(三)基本垃圾回收算法

可以从不同的的角度去划分垃圾回收算法: 按照基本回收策略分 引用计数(Reference Counting): 比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对象。此算法最致命的是无法处理循环引用的问题。 标记-清除(Mark-Sweep): 此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。 复制(Copying):

此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。次算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间。 标记-整理(Mark-Compact):

此算法结合了“标记-清除”和“复制”两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象“压缩”到堆的其中一块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。 按分区对待的方式分 增量收集(Incremental Collecting):实时垃圾回收算法,即:在应用进行的同时进行垃圾回收。不知道什么原因JDK5.0中的收集器没有使用这种算法的。 分代收集(Generational Collecting):基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法(上述方式中的一个)进行回收。现在的垃圾回收器(从J2SE1.2开始)都是使用此算法的。 按系统线程分 串行收集:串行收集使用单线程处理所有垃圾回收工作,因为无需多线程交互,实现容易,而且效率比较高。但是,其局限性也比较明显,即无法使用多处理器的优势,所以此收集适合单处理器机器。当然,此收集器也可以用在小数据量(100M左右)情况下的多处理器机器上。 并行收集:并行收集使用多线程处理垃圾回收工作,因而速度快,效率高。而且理论上CPU数目越多,越能体现出并行收集器的优势。 并发收集:相对于串行收集和并行收集而言,前面两个在进行垃圾回收工作时,需要暂停整个运行环境,而只有垃圾回收程序在运行,因此,系统在垃圾回收时会有明显的暂停,而且暂停时间会因为堆越大而越长。

两种常见的内存管理方法:堆和内存池

两种常见的内存管理方法:堆和内存池 本文导读 在程序运行过程中,可能产生一些数据,例如,串口接收的数据,ADC采集的数据。若需将数据存储在内存中,以便进一步运算、处理,则应为其分配合适的内存空间,数据处理完毕后,再释放相应的内存空间。为了便于内存的分配和释放,AWorks提供了两种内存管理工具:堆和内存池。 本文为《面向AWorks框架和接口的编程(上)》第三部分软件篇——第9章内存管理——第1~2小节:堆管理器和内存池。 本章导读 在计算机系统中,数据一般存放在内存中,只有当数据需要参与运算时,才从内存中取出,交由CPU运算,运算结束再将结果存回内存中。这就需要系统为各类数据分配合适的内存空间。 一些数据需要的内存大小在编译前可以确定。主要有两类:一类是全局变量或静态变量,这部分数据在程序的整个生命周期均有效,在编译时就为这些数据分配了固定的内存空间,后续直接使用即可,无需额外的管理;一类是局部变量,这部分数据仅在当前作用域中有效(如函数中),它们需要的内存自动从栈中分配,也无需额外的管理,但需要注意的是,由于这一部分数据的内存从栈中分配,因此,需要确保应用程序有足够的栈空间,尽量避免定义内存占用较大的局部变量(比如:一个占用数K内存的数组),以避免栈溢出,栈溢出可能破坏系统关键数据,极有可能造成系统崩溃。 一些数据需要的内存大小需要在程序运行过程中根据实际情况确定,并不能在编译前确定。例如,可能临时需要1K内存空间用于存储远端通过串口发过来的数据。这就要求系统具有对内存空间进行动态管理的能力,在用户需要一段内存空间时,向系统申请,系统选择一段合适的内存空间分配给用户,用户使用完毕后,再释放回系统,以便系统将该段内存空间回收再利用。在AWorks中,提供了两种常见的内存管理方法:堆和内存池。9.1 堆管理器

一种嵌入式系统的内存分配方案

一种嵌入式系统的内存分配方案 摘要:实时性、可靠性的要求,使得许多嵌入式应用使用自己的内存管理程序。本文探讨嵌入式系统中对内存管理的要求、存在的问题以及可能的解决策略;介绍一种“一次分配,多次使用”的动态内存分配方法,并给出2个例子。 关键词:嵌入式系统内存管理一次分配多次使用 1 嵌入式系统中对内存分配的要求 ①快速性。嵌入式系统中对实时性的保证,要求内存分配过程要尽可能地快。因此在嵌入式系统中,不可能采用通用操作系统中复杂而完善的内存分配策略,一般都采用简单、快速的内存分配方案。当然,对实性要求的程序不同,分配方案也有所不同。例如,VxWorks采用简单的最先匹配如立即聚合方法;VRTX中采用多个固定尺寸的binning方案。 ②可靠性。也就是内存分配的请求必须得到满足,如果分配失败可能会带来灾难性的后果。嵌入式系统应用的环境千变万化,其中有一些是对可靠性要求极高的。比如,汽车的自动驾驶系统中,系统检测到即将撞车,如果因为内存分配失败而不能相应的操作,就会发生车毁人亡的事故,这是

不能容忍的。 ③高效性。内存分配要尽可能地少浪费。不可能为了保证满足所有的内存分配请求而将内存配置得无限大。一方面,嵌入式系统对成本的要求使得内存在其中只是一种很有限的资源;另一方面,即使不考虑成本的因素,系统有限的空间和有限的板面积决定了可配置的内存容量是很限的。 静态分配与动态分配 究竟应用使用静态分配还是动态分配,一直是嵌入式系统设计中一个争论不休的总是。当然,最合适的答案是对于不同的系统采用不同的方案。如果是系统对于实时性和可靠性的要求极高,不能容忍一点延时或者一次分配失败,当然需要采用静态分配方案,也就是在程序编译时所需要的内存都已经分配好了。例如,火星探测器上面的嵌入式系统就必须采用静态分配的方案。另外,WindRiver公司的一款专门用于汽车电子和工业自动化领域的实时操作系统OSEKWorks中就不支持内存的动态分配。在这样的应用场合,成本不支持内存的动态分配。在这样的应用场合,成本不是优先考虑的对象,实时性和可靠性才是必须保证的。当然,采用静态分配一个不可避免的总是就是系统失去了灵活性,必须在设计阶段就预先知道所需要的内存并对之作出分配;必须在设计阶段就预先考虑到所有可能的情况,因为一旦出现没有考虑到的情况,系统就无法处理。这样的分配方

JVM内存分配(栈堆)与JVM回收机制

Java 中的堆和栈 简单的说: Java把内存划分成两种:一种是栈内存,一种是堆内存。 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。 堆内存用来存放由new创建的对象和数组。 在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。 在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。 引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。 具体的说: 栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。 Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。 栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。 栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义: int a = 3; int b = 3; 编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b 的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。 String是一个特殊的包装类数据。可以用: String str = new String("abc"); String str = "abc"; 两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。 而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc”则直接令 str指向“abc”。 比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。 String str1 = "abc"; String str2 = "abc"; System.out.println(str1==str2); //true

Eclipse中JVM内存设置

Eclipse中JVM内存设置 eclipse.ini内存设置 -vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M 这里有几个问题: 1. 各个参数的含义什么? 2. 为什么有的机器我将-Xmx和-XX:MaxPermSize都设置为512M之后Eclipse可以启动,而有些机器无法启动? 3. 为何将上面的参数写入到eclipse.ini文件Eclipse没有执行对应的设置? 下面我们一一进行回答 1. 各个参数的含义什么? 参数中-vmargs的意思是设置JVM参数,所以后面的其实都是JVM的参数了,我们首先了解一下JVM内存管理的机制,然后再解释每个参数代表的含义。 堆(Heap)和非堆(Non-heap)内存 按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memo ry)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。 堆内存分配

JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-X mx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。 非堆内存分配 JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxP ermSize设置最大非堆内存的大小,默认是物理内存的1/4。 JVM内存限制(最大值) 首先JVM内存限制于实际的最大物理内存(废话!呵呵),假设物理内存无限大的话,J VM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows 系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了。 2. 为什么有的机器我将-Xmx和-XX:MaxPermSize都设置为512M之后Eclipse可以启动,而有些机器无法启动? 通过上面对JVM内存管理的介绍我们已经了解到JVM内存包含两种:堆内存和非堆内存,另外JVM最大内存首先取决于实际的物理内存和操作系统。所以说设置VM参数导致程序无法启动主要有以下几种原因: 1) 参数中-Xms的值大于-Xmx,或者-XX:PermSize的值大于-XX:MaxPermSize; 2) -Xmx的值和-XX:MaxPermSize的总和超过了JVM内存的最大限制,比如当前操作系统最大内存限制,或者实际的物理内存等等。说到实际物理内存这里需要说明一点的是,如果你的内存是1024MB,但实际系统中用到的并不可能是1024MB,因为有一部分被硬件占用了。 3. 为何将上面的参数写入到eclipse.ini文件Eclipse没有执行对应的设置?

JVM的垃圾回收机制小读

JVM的垃圾回收机制小读 技术2010-05-09 19:41:04 阅读20 评论2 字号:大中小订阅 今天下午突然遇到了一个内存漏洞的问题,所以上网查了查,结果看到了一篇文章,说的是jvm的垃圾回收机制,下面粘过来,看了好久才看完的,说的思路有点含糊,还给带了点代码,这样还不错……对JVM 的内存管理机制有加深了一层理解哈………… 下面是那篇文章,喜欢的可以看看…………O(∩_∩)O………… Java的堆是一个运行时数据区,类的实例(对象)从中分配空间。Java虚拟机(JVM)的堆中储存着正在运行的应用程序所建立的所有对象,这些对象通过new、newarray、anewarray和multianewarray等指令建立, 但是它们不需要程序代码来显式地释放。 引言 Java的堆是一个运行时数据区,类的实例(对象)从中分配空间。Java虚拟机(JVM)的堆中储存着正在运行的应用程序所建立的所有对象,这些对象通过new、newarray、anewarray和multianewarray等指令建立,但是它们不需要程序代码来显式地释放。一般来说,堆的是由垃圾回收来负责的,尽管JVM规范并不要求特殊的垃圾回收技术,甚至根本就不需要垃圾回收,但是由于内存的有限性,JVM在实现的时候都有一个由垃圾回收所管理的堆。垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,按照特定的垃圾收集算法来实现资源自动回收的功能。 垃圾收集的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象;而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。垃圾收集意味着程序不再需要的对象是"无用信息",这些信息将被丢弃。当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用。事实上,除了释放没用的对象,垃圾收集也可以清除内存记录碎片。由于创建对象和垃圾收集器释放丢弃对象所占的内存空间,内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存洞。碎片整理将所占用的堆内存移到堆 的一端,JVM将整理出的内存分配给新的对象。 垃圾收集能自动释放内存空间,减轻编程的负担。这使Java 虚拟机具有一些优点。首先,它能使编程效率提高。在没有垃圾收集机制的时候,可能要花许多时间来解决一个难懂的存储器问题。在用Java 语言编程的时候,靠垃圾收集机制可大大缩短时间。其次是它保护程序的完整性,垃圾收集是Java语言 安全性策略的一个重要部份。 垃圾收集的一个潜在的缺点是它的开销影响程序性能。Java虚拟机必须追踪运行程序中有用的对象,而且最终释放没用的对象。这一个过程需要花费处理器的时间。其次垃圾收集算法的不完备性,早先采用的某些垃圾收集算法就不能保证100%收集到所有的废弃内存。当然随着垃圾收集算法的不断改进以及软硬件运行效率的不断提升,这些问题都可以迎刃而解。 垃圾收集的算法分析

JAVA虚拟机内存分配机制

JA V A虚拟机内存分配原则 Java把内存划分成两种:一种是栈内存,一种是堆内存。 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。 堆内存用来存放由new创建的对象和数组。 在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。 在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。 引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。 具体的说: 栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。 Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java 的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。 栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。 栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义: int a = 3; int b = 3;

JVM内存大小配置方式

JVM内存大小配置方式 By:sheagle@https://www.doczj.com/doc/ad24289.html, 1.最简单的方式,tomcat当中进行配置 用记事本打开tomcat安装路径下bin文件夹中的Catalina.bat,在文件当中添加set JAV A_OPTS=-Xms256m-Xmx512m 该方式只适合于使用Catalina Start指令及其类似方式通过执行Startup.bat中的指令方式启动tomcat 2.在Eclipse当中配置tomcat的内存启动大小 Eclipse->Window->Preferences->Server->Runtime Environments->选中Apache Tomcat v5.0->点击Edit按钮->在弹出对话框里点击JRE后面的Installed JREs按钮->在弹出对话框中选中tomcat使用的那个JRE->点击Edit按钮->在弹出对话框中,找到Default VM Arguments,并在输入框中输入:-Xms256M-Xmx512M 该修改方式只适合于使用Eclipse启动tomcat 3.在注册表中修改tomcat大小 如果你的电脑上边安装了tomcat服务,那么你也可以通过以下设置来修改通过

服务启动时的tomcat内存。 打开tomcat安装路径下bin文件夹中的tomcat6w.exe。选中Java,修改Inital memory pool和Maximum memory pool 该修改方式只适合于使用“服务”方式启动tomcat 总结: 关于tomcat启动时JVM虚拟机内存大小的配置,针对每种情况会有多种不同的配置方式,基本上都是修改配 置文件中参数的大小,无论使用哪种配置方式进行配置,只要能达到效果即可

Java JVM参数设置及日志查看

基础知识-Java JVM参数设置及日志查看 JVM内存参数 -Xms:初始堆大小;默认值为物理内存的1/64(<1GB),默认(MinHeapFreeRatio 参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制。-Xmx:最大堆大小;默认值为物理内存的1/4(<1GB) 默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制 -Xmn:年轻代大小(1.4or lator);注意:此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不同的。整个堆大小=年轻代大小+ 年老代大小+ 持久代大小。增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8 -XX:NewSize:设置年轻代大小(for 1.3/1.4) -XX:MaxNewSize:年轻代最大值(for 1.3/1.4) -XX:PermSize:设置持久代(perm gen)初始值物理内存的1/64 -XX:MaxPermSize:设置持久代最大值;默认值为物理内存的1/4。注意IBM的JDK设置此参数无效。 -Xss:每个线程的堆栈大小;JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。一般小的应用,如果栈不是很深,应该是128k够用的大的应用建议使用256k。这个选项对性能影响比较大,需要严格的选择。 -XX:ThreadStackSize:Thread Stack Size;(0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.],此值设置和-Xss设置相似,目前较多使用-Xss。 -XX:NewRatio:年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)-XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5 当Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。 -XX:SurvivorRatio:Eden区与Survivor区的大小比值;设置为8,则两个Survivor 区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10 -XX:LargePageSizeInBytes:内存页的大小不可设置过大,会影响Perm的大小,默认为128m -XX:+UseFastAccessorMethods:原始类型的快速优化 -XX:+DisableExplicitGC:关闭System.gc();这个参数谨慎使用。 -XX:MaxTenuringThreshold:垃圾最大年龄;如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率,该参数只有在串行GC时才有效。 -XX:+AggressiveOpts:加快编译 -XX:+UseBiasedLocking:锁机制的性能改善

JVM内存管理:深入垃圾收集器与内存分配策略

JVM内存管理:深入垃圾收集器与内存分配策略 https://www.doczj.com/doc/ad24289.html, 时间:2010-11-20 作者:网络编辑:fnw 点击: 6 [ 评论] - - Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来。 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项技术当做Java 语言的伴生产物。事实上GC的历史远远比Java来得久远,在1960年诞生于MIT的Lisp 是第一门真正使用内存动态分配和垃圾收集技术的语言。当Lisp还在胚胎时期,人们就在思考GC需要完成的3件事情:哪些内存需要回收?什么时候回收?怎么样回收? 经过半个世纪的发展,目前的内存分配策略与垃圾回收技术已经相当成熟,一切看起来都进入“自动化”的时代,那为什么我们还要去了解GC和内存分配?答案很简单:当需要排查各种内存溢出、泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就需要对这些“自动化”的技术有必要的监控、调节手段。 把时间从1960年拨回现在,回到我们熟悉的Java语言。本文第一章中介绍了Java内存运行时区域的各个部分,其中程序计数器、VM栈、本地方法栈三个区域随线程而生,随线程而灭;栈中的帧随着方法进入、退出而有条不紊的进行着出栈入栈操作;每一个帧中分配多少内存基本上是在Class文件生成时就已知的(可能会由JIT动态晚期编译进行一些优化,但大体上可以认为是编译期可知的),因此这几个区域的内存分配和回收具备很高的确定性,因此在这几个区域不需要过多考虑回收的问题。而Java堆和方法区(包括运行时常量池)则不一样,我们必须等到程序实际运行期间才能知道会创建哪些对象,这部分内存的分配和回收都是动态的,我们本文后续讨论中的“内存”分配与回收仅仅指这一部分内存。 对象已死? 在堆里面存放着Java世界中几乎所有的对象,在回收前首先要确定这些对象之中哪些还在存活,哪些已经“死去”了,即不可能再被任何途径使用的对象。 引用计数算法(Reference Counting) 最初的想法,也是很多教科书判断对象是否存活的算法是这样的:给对象中添加一个引用计数器,当有一个地方引用它,计数器加1,当引用失效,计数器减1,任何时刻计数器为0的对象就是不可能再被使用的。 客观的说,引用计数算法实现简单,判定效率很高,在大部分情况下它都是一个不错的算法,但引用计数算法无法解决对象循环引用的问题。举个简单的例子:对象A和B分别有字段b、a,令A.b=B和B.a=A,除此之外这2个对象再无任何引用,那实际上这2个对

JVM内存最大能调多大分析

JVM内存最大能调多大分析【经典】 2010-11-10 13:21 转载自 最终编辑 上次用weblogic 把 -XmxXXXX 设成2G,就启动不起来,设小点就起来了,当时很气,怎么2G都起不了,今天在看到了一篇解释,转过来了 这次一位老友提出了这个问题,记得当年一个java高手在blogjava提出后,被骂得半死。大家使用java -XmxXXXX -version版本得出了不同的结论。后来老友说大概是1800M左右,我当时反驳,“我设置过服务器8G内存,我使用两个tomcat,每个2G”。为此,我翻开所有的JVM的内存管理的c代码,没有任何结论。我不是linux内核程序员,但是我看过linux的源码,知道32位体系结构的计算机寻址空间是2^32=4G,intel Pentium Pro处理器寻址空间是36位,CPU内部增加了PAE寄存器。用于处理多出来的4根地址 线的使用,所以PAE的技术实现最大2^36=64G寻址。通过linux的内核源码,标准Linux内核对于物理内存的管理采用1:3的分配比例,即物理内存的1/4为内核空间(kernel space),剩下的3/4为用户进程空间(user space),因此,在一台4G内存的服务器上,用户进程可使用的内存最大也就是3G。当进程被内核调入CPU运行时,不同的地址空间数据会被调入4G以内的用户进程空间,其实就能用3G。 IA32架构上,单一进程是不能使用超过4G的内存空间的。但是我记得我给mysql server分配内存大约是左右,不是2的32次方-1,我分配java 2G内存的计算机是IBM的RS6000. 经过不同平台的测试,我得出了大概的数值,win2k下左右,nt下,原因是这样的,Classic VM and HotSpot VM 存放用户区的连续地址中,NT把 kernel DLLs 放在 0x7c 开头的地址空间,所以nt下只有<2G的空间,所以JVM heap 使用极限是2G.用户的dll开始于0x,用户的应用程序开始于0x00400000.我现在唯一确定的是sun可能为了防止和某些 JVM插件的冲突,把dll的地址给rebase一下,这样使用的空间就很少了一部分.为什末rebase,原因是这样的,因为在windows下编译 dll 的默认地址都是, 一般在release之前的时候要rebase一下,rebase 的-b 这个参数是指定一个起始地址,MSDN建议地址是0x,这个工具随visual studio和platform SDK发放。 例如 -b 0x6D000000 \jdk\jre\bin\*.dll \jdk\jre\bin\hotspot\这样你的JVM用的内存多一些,目前关于这个我只能得到BEA的 JRockit最大也只能使用内存,看来各家编译JDK时都作了些手脚. 目前只能得到bea的的-Xmx最小值是16 MB,sun的资料很不全,还好java开源了,可以不依靠sun了. sun提供的资料 Maximum Address Space Per Process Operating System Maximum Address Space Per Process

JVM调优总结

JVM调优总结 作者: 和你在一起https://www.doczj.com/doc/ad24289.html, 程序员其实很痛苦的,每隔一段时间就会听到、看到很多很多新名词、新技术---囧.幸而有了互联网,有了开源、有了wiki、有了分享:)—人人为我,我为人人。拓荒者走过的时候很痛苦,但是如果能给后来人留下点路标,是不是可以让他们少走一些弯路呢?踏着前辈的足迹我走到了这里,也应该为后来的人留下点东西。走夜路其实不可怕,可怕的是一个人走夜路:)https://www.doczj.com/doc/ad24289.html, - 做最棒的软件开发交流社区 A-PDF Number Pro DEMO: Purchase from https://www.doczj.com/doc/ad24289.html, to remove the watermark

目 录 1. java路上 1.1 JVM调优总结-序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 1.2 JVM调优总结(一)-- 一些概念 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4 1.3 JVM调优总结(二)-一些概念 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7 1.4 JVM调优总结(三)-基本垃圾回收算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9 1.5 JVM调优总结(四)-垃圾回收面临的问题 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12 1.6 JVM调优总结(五)-分代垃圾回收详述1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14 1.7 JVM调优总结(六)-分代垃圾回收详述2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18 1.8 JVM调优总结(七)-典型配置举例1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26 1.9 JVM调优总结(八)-典型配置举例2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .31 1.10 JVM调优总结(九)-新一代的垃圾回收算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .34 1.11 JVM调优总结(十)-调优方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .38 1.12 JVM调优总结(十一)-反思 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .47 1.13 JVM调优总结(十二)-参考资料 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .50

JVM调优

首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提供的内存查看工具,比如JConsole和Java VisualVM。 对JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数,过多的GC和Full GC是会占用很多的系统资源(主要是CPU),影响系统的吞吐量。特别要关注Full GC,因为它会对整个堆进行整理,导致Full GC一般由于以下几种情况: 旧生代空间不足 调优时尽量让对象在新生代GC时被回收、让对象在新生代多存活一段时间和不要创建过大的对象及数组避免直接在旧生代创建对象 Pemanet Generation空间不足 增大Perm Gen空间,避免太多静态对象 统计得到的GC后晋升到旧生代的平均大小大于旧生代剩余空间 控制好新生代和旧生代的比例 System.gc()被显示调用 垃圾回收不要手动触发,尽量依靠JVM自身的机制 调优手段主要是通过控制堆内存的各个部分的比例和GC策略来实现,下面来看看各部分比例不良设置会导致什么后果 1)新生代设置过小 一是新生代GC次数非常频繁,增大系统消耗;二是导致大对象直接进入旧生代,占据了旧生代剩余空间,诱发Full GC

2)新生代设置过大 一是新生代设置过大会导致旧生代过小(堆总量一定),从而诱发Full GC;二是新生代GC耗时大幅度增加 一般说来新生代占整个堆1/3比较合适 3)Survivor设置过小 导致对象从eden直接到达旧生代,降低了在新生代的存活时间 4)Survivor设置过大 导致eden过小,增加了GC频率 另外,通过-XX:MaxTenuringThreshold=n来控制新生代存活时间,尽量让对象在新生代被回收 由内存管理和垃圾回收可知新生代和旧生代都有多种GC策略和组合搭配,选择这些策略对于我们这些开发人员是个难题,JVM提供两种较为简单的GC策略的设置方式 1)吞吐量优先 JVM以吞吐量为指标,自行选择相应的GC策略及控制新生代与旧生代的大小比例,来达到吞吐量指标。这个值可由-XX:GCTimeRatio=n来设置 2)暂停时间优先 JVM以暂停时间为指标,自行选择相应的GC策略及控制新生代与旧生代的大小比例,尽量保证每次GC造成的应用停止时间都在指定的数值范围内完成。这个值可由-XX:MaxGCPauseRatio=n来设置

可变分区存储管理方案中的内存分配

可变分区存储管理方案中的内存分配 用户提出内存空间的申请;系统根据申请者的要求, 按照一定的分配策略分析内存空间的使用情况,找出能满足请求的空闲区,分给申请者;当程序执行完毕或主动归还内存资源时, 系统要收回它所占用的内存空间或它归还的部分内存空间。 1.程序运行时首先接收输入:空闲区数据文件,包括若干行, 每行有两个数据项:起始地址、长度(均为整数),各数据项以逗号隔开。 2.建立空闲区表并在屏幕上显示输出空闲区表内容, 空闲区表中记录了内存中可供分配的空闲区的始址和长度, 用标志位指出该分区是否是未分配的空闲区。 3.从用户界面根据用户提示接收一个内存申请,格式为:作业名、申请空间的大小。 4.按照最差(最坏)适配算法选择一个空闲区,分割并分配, 修改相应的数据结构(空闲区表),填写内存已分配区表(起始地址、长度、标志位),其中标志位的一个作用是指出该区域分配给哪个作业。 5.重复3、4,直到输入为特殊字符(0)。 6.在屏幕上显示输出新的空闲区表和已分配区表的内容 #include #include #include #define MAX 10 struct data1 /*空闲区表*/ { int address; int length; int flag; }; struct data2 /*已分配区表*/ { int address; int length; char name[20]; }; struct data1 empty[MAX]; struct data2 busy[MAX];

void initialize( ); int read_data( ); /*从文件中读如数据*/ void display_empty_table(int); /*显示空闲区表*/ void display_busy_table(int); /*显示已分配区表*/ void badest_fit( int *,int *,char *name,int s );/*最坏适应算法*/ void first_fit( int *,int *,char *name,int s ); /*最先适应算法*/ void best_fit( int *,int *,char *name,int s ); /*最佳适应算法*/ void main( ) { int num1,num2,size; /*num1用于统计空闲表的,num2用于统计分配区表*/ char name[20]; num2=0; initialize( ); /*初始花空闲区表和分配区表*/ num1=read_data( ); if( num1==0 ) /*表示文件中没有数据*/ printf("there has no data in empty table\n"); printf("the initialial empty table is:\n"); display_empty_table( num1 ); /*显示空闲区表*/ while(1) { printf("please input job's name and job's size\n"); puts("input exit to exit"); scanf("%s",name); if( strcmp(name,"exit")==0 ) { getch( ); break; } scanf("%d",&size); badest_fit( &num1,&num2,name,size );/*这里可以改为最佳适应和最先适应*/ } puts("the empty table after assigning"); display_empty_table( num1 ); puts("the busy table:"); display_busy_table( num2 ); } void initialize( ) { int i; for( i=0;i

相关主题
文本预览
相关文档 最新文档