- 1、内存管理简介
   
  
 内存管理的职责为分配内存,回收内存。
 没有自动内存管理的语言/平台容易发生错误。
 典型的问题包括悬挂指针问题,一个指针引用了一个已经被回收的内存地址,导致程序的运行完全不可知。
 另一个典型问题为内存泄露,内存已经分配,但是已经没有了指向该内存的指针,导致内存泄露。
 程序员要花费大量时间在调试该类问题上。
 
 2、GC简介
 因此引入了Garbage Collector机制,由运行时环境来自动管理内存。
 Garbage Collector解决了悬挂指针和内存泄露大部分的问题(不是全部)。
 
 注意Garbage Collector(简称Collector)和Garbage Collection(简称GC)的区别。
 
 3、Collector的职责:
 分配内存。
 保证有引用的内存不被释放。
 回收没有指针引用的内存。
 
 对象被引用称为活对象,对象没有被引用称为垃圾对象/垃圾/垃圾内存,找到垃圾对象并回收是Collector的一个主要工作,该过程称为GC。
 
 Collector一般使用一个称为堆的内存池来进行内存的分配和回收。
 一般的,当堆内存满或者达到一个阀值时,堆内存或者部分堆内存被GC。
  4、好的Collector的特性 
保证有引用的对象不被GC。
快速的回收内存垃圾。
在程序运行期间GC要高效,尽量少的影响程序运行。和大部分的计算机问题一样,这是一个关于空间,时间,效率平衡的问题。
避免内存碎片,内存碎片导致占用大量内存的大对象内存申请难以满足。可以采用Compaction技术避免内存碎片。Compaction技术:把活对象移向连续内存区的一端,回收其余的内存以便以后的分配。
良好的扩展性,内存分配和GC在多核机器上不应该成为性能瓶颈。
 
 保证有引用的对象不被GC。
快速的回收内存垃圾。
在程序运行期间GC要高效,尽量少的影响程序运行。和大部分的计算机问题一样,这是一个关于空间,时间,效率平衡的问题。
避免内存碎片,内存碎片导致占用大量内存的大对象内存申请难以满足。可以采用Compaction技术避免内存碎片。Compaction技术:把活对象移向连续内存区的一端,回收其余的内存以便以后的分配。
良好的扩展性,内存分配和GC在多核机器上不应该成为性能瓶颈。
  5、GC性能指标 
Throughput: 程序时间(不包含GC时间)/总时间。
GC overhead: GC时间/总时间。
Pause time: GC运行时程序挂起时间。
Frequency of GC: GC频率。
Footprint: a measure of size, such as heap size。
Promptness:对象变为垃圾到该垃圾被回收后内存可用的时间。
 
依赖于不同的场景,对于GC的性能指标的关注点也不一样。
 
6、分代GC
分代GC把内存划分为多个代(内存区域),每个代存储不同年龄的对象。 常见的分为2代,young和old。
分配内存时,先从young代分配,如果young代已满,可以执行GC(可能导致对象提升),如果有空间,则分配,如果young代还是没有空间,可以对整个内存堆GC。
young代GC后还存活的对象可以提升到old代。
该机制基于以下观察事实:
1 大部分新分配的对象很快就没有引用了,变成垃圾。
2 很少有old代对象引用young代对象。
基于代内存存储对象的特性,对不同代的内存可以使用不同的GC算法。
Young代GC需要高效,快速,频繁的执行,关注点主要在速度上。
Old代由于增长缓慢,因此GC不频繁,但是其内存空间比较大,因此,需要更长时间才能执行完GC。关注点在内存空间利用率上。
 
 Throughput: 程序时间(不包含GC时间)/总时间。
GC overhead: GC时间/总时间。
Pause time: GC运行时程序挂起时间。
Frequency of GC: GC频率。
Footprint: a measure of size, such as heap size。
Promptness:对象变为垃圾到该垃圾被回收后内存可用的时间。
依赖于不同的场景,对于GC的性能指标的关注点也不一样。
6、分代GC
分代GC把内存划分为多个代(内存区域),每个代存储不同年龄的对象。 常见的分为2代,young和old。
分配内存时,先从young代分配,如果young代已满,可以执行GC(可能导致对象提升),如果有空间,则分配,如果young代还是没有空间,可以对整个内存堆GC。
young代GC后还存活的对象可以提升到old代。
该机制基于以下观察事实:
1 大部分新分配的对象很快就没有引用了,变成垃圾。
2 很少有old代对象引用young代对象。
基于代内存存储对象的特性,对不同代的内存可以使用不同的GC算法。
Young代GC需要高效,快速,频繁的执行,关注点主要在速度上。
Old代由于增长缓慢,因此GC不频繁,但是其内存空间比较大,因此,需要更长时间才能执行完GC。关注点在内存空间利用率上。
  7、Java Collector 
Jvm的内存分为3代。Young, Old, Permanent。
大部分对象存储在Young代。
在Young代中经历数次GC存活的对象可以提升到Old代,大对象也可以直接分配到Old代。
Permanent代保存虚拟机自己的静态(refective)数据,例如类(class)和方法(method)对象。
Young代由一个Eden和2个survivor组成。大部分的对象的内存分配和回收在这里完成。
 
Survivor存储至少经过一次GC存活下来的对象,以增大该对象在提升至old代前被回收的机会。2个survivor中有一个为空。分别为From和to survivor。
 
当young代内存满,执行young代GC(minor GC)。
当old或permanent代内存满,执行full GC(major GC),所有代都被GC。一般先执行young GC,再执行old, permanent GC。
有时old代太满,以至于如果young GC先运行,则无法存储提升的对象。这时,Young GC不运行,old GC算法在整个堆上运行(CMS collector是个例外,该collector不能运行在young 代上)。
 
 Jvm的内存分为3代。Young, Old, Permanent。
大部分对象存储在Young代。
在Young代中经历数次GC存活的对象可以提升到Old代,大对象也可以直接分配到Old代。
Permanent代保存虚拟机自己的静态(refective)数据,例如类(class)和方法(method)对象。
Young代由一个Eden和2个survivor组成。大部分的对象的内存分配和回收在这里完成。
Survivor存储至少经过一次GC存活下来的对象,以增大该对象在提升至old代前被回收的机会。2个survivor中有一个为空。分别为From和to survivor。
当young代内存满,执行young代GC(minor GC)。
当old或permanent代内存满,执行full GC(major GC),所有代都被GC。一般先执行young GC,再执行old, permanent GC。
有时old代太满,以至于如果young GC先运行,则无法存储提升的对象。这时,Young GC不运行,old GC算法在整个堆上运行(CMS collector是个例外,该collector不能运行在young 代上)。
- 调优
-  年轻代大小选择
 - 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。
- 吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。
 
-  年老代大小选择 
   -  响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得: 
     - 并发垃圾收集信息
- 持久代并发收集次数
- 传统GC信息
- 花在年轻代和年老代回收上的时间比例
 
- 吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。
 
-  响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得: 
     
-  较小堆引起的碎片问题
 因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩。当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记、清除方式进行回收。如果出现“碎片”,可能需要进行如下配置:- -XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。
- -XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩
 
 
 JVM给了三种选择:
 串行收集器、并行收集器、并发收集器
 ,但是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器。默认情况下,JDK5.0以前都是使用串行收集器,如果想使用其他收集器需要在启动时加入相应参数。JDK5.0以后,JVM会根据当前
 系统配置
 进行判断。 
 
 
 
-  吞吐量优先的并行收集器
 如上文所述,并行收集器主要以到达一定的吞吐量为目标,适用于科学技术和后台处理等。
 典型配置:-  java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
 -XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。
 -XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。
 
-  java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC
 -XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集。
 
-  java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC  -XX:MaxGCPauseMillis=100
 -XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。
 
-  java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC  -XX:MaxGCPauseMillis=100-XX:+UseAdaptiveSizePolicy
 -XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。
 
-  java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
-  响应时间优先的并发收集器
 如上文所述,并发收集器主要是保证系统的响应时间,减少垃圾收集时的停顿时间。适用于应用服务器、电信领域等。
 典型配置:-  java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
 -XX:+UseConcMarkSweepGC:设置年老代为并发收集。测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明。所以,此时年轻代大小最好用-Xmn设置。
 -XX:+UseParNewGC:设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值。
-  java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
 -XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。
 -XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但是可以消除碎片
 
-  java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-  堆设置 
   - -Xms:初始堆大小
- -Xmx:最大堆大小
- -XX:NewSize=n:设置年轻代大小
- -XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
- -XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
- -XX:MaxPermSize=n:设置持久代大小
 
-  收集器设置 
   - -XX:+UseSerialGC:设置串行收集器
- -XX:+UseParallelGC:设置并行收集器
- -XX:+UseParalledlOldGC:设置并行年老代收集器
- -XX:+UseConcMarkSweepGC:设置并发收集器
 
-  垃圾回收统计信息 
   - -XX:+PrintGC
- -XX:+PrintGCDetails
- -XX:+PrintGCTimeStamps
- -Xloggc:filename
 
-  并行收集器设置 
   - -XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
- -XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
- -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
 
-  并发收集器设置 
   - -XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
- -XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。
 
 
 jmap –histo pid 查询各种对象占用的内存大小。 
 
 
 

 
 jstat -gcutil 25126 6000 200   查看gc回收情况
 
 

 
  jmap -heap 25126  查看tomcat jvm内存分配情况
 
 

 
                   
                   
                   
                   
                             本文详细介绍了JVM内存管理的基本概念,重点阐述了GC的工作原理、特性及性能指标,通过分代GC机制优化内存分配和回收。文章还提供了针对不同应用场景的GC性能调优策略,包括年轻代和年老代大小的选择、并发收集器的配置等,旨在帮助开发者实现高效、稳定的Java应用。
本文详细介绍了JVM内存管理的基本概念,重点阐述了GC的工作原理、特性及性能指标,通过分代GC机制优化内存分配和回收。文章还提供了针对不同应用场景的GC性能调优策略,包括年轻代和年老代大小的选择、并发收集器的配置等,旨在帮助开发者实现高效、稳定的Java应用。
           
       
           
                 
                 
                 
                 
                 
                
               
                 
                 
                 
                 
                
               
                 
                 扫一扫
扫一扫
                     
              
             
                   746
					746
					
 被折叠的  条评论
		 为什么被折叠?
被折叠的  条评论
		 为什么被折叠?
		 
		  到【灌水乐园】发言
到【灌水乐园】发言                                
		 
		 
    
   
    
   
             
            


 
            