精华内容
下载资源
问答
  • 内存管理简介 内存管理的职责为分配内存,回收内存。 没有自动内存管理的语言/平台容易发生错误。 典型的问题包括悬挂指针问题,一个指针... GC简介 因此引入了Garbage Collector机制,由运行时环境来自动管...

    内存管理简介 
    内存管理的职责为分配内存,回收内存。 
    没有自动内存管理的语言/平台容易发生错误。 
    典型的问题包括悬挂指针问题,一个指针引用了一个已经被回收的内存地址,导致程序的运行完全不可知。 
    另一个典型问题为内存泄露,内存已经分配,但是已经没有了指向该内存的指针,导致内存泄露。 
    程序员要花费大量时间在调试该类问题上。 

    GC简介 
    因此引入了Garbage Collector机制,由运行时环境来自动管理内存。 
    Garbage Collector解决了悬挂指针和内存泄露大部分的问题(不是全部)。 

    注意Garbage Collector(简称Collector)和Garbage Collection(简称GC)的区别。 

    Collector的职责: 
    分配内存。 
    保证有引用的内存不被释放。 
    回收没有指针引用的内存。 

    对象被引用称为活对象,对象没有被引用称为垃圾对象/垃圾/垃圾内存,找到垃圾对象并回收是Collector的一个主要工作,该过程称为GC。 

    Collector一般使用一个称为堆的内存池来进行内存的分配和回收。 
    一般的,当堆内存满或者达到一个阀值时,堆内存或者部分堆内存被GC。 

    好的Collector的特性 
    保证有引用的对象不被GC。 
    快速的回收内存垃圾。 
    在程序运行期间GC要高效,尽量少的影响程序运行。和大部分的计算机问题一样,这是一个关于空间,时间,效率平衡的问题。 
    避免内存碎片,内存碎片导致占用大量内存的大对象内存申请难以满足。可以采用Compaction技术避免内存碎片。Compaction技术:把活对象移向连续内存区的一端,回收其余的内存以便以后的分配。 
    良好的扩展性,内存分配和GC在多核机器上不应该成为性能瓶颈。 


    设计或选择Collector 
    串行或并行。 
    串行Collector在多核上也只有一个线程在运行,并行Collector可以同时有多个线程执行GC,但是其算法更复杂。 
    并发或Stop the World。 
    Stop the World Collection执行GC时,需要冻住所有内存,因此更简单一些,但是,在GC时,程序是被挂起的。并发GC时,程序和GC同时执行,当然,一般的并发GC算法还是需要一些Stop the World时间。 
    Compacting or Non-compacting or Copying 
    Compacting: 去除内存碎片,回收内存慢,分配内存快。 
    Non-compacting: 容易产生内存碎片,回收内存快,分配内存慢,对大对象内存分配支持不好。 
    Copying: 复制活对象到新的内存区域,原有内存直接回收,需要额外的时间来做复制,额外的空间来做存储。 

    GC性能指标 
    Throughput: 程序时间(不包含GC时间)/总时间。 
    GC overhead: GC时间/总时间。 
    Pause time: GC运行时程序挂起时间。 
    Frequency of GC: GC频率。 
    Footprint: a measure of size, such as heap size。 
    Promptness:对象变为垃圾到该垃圾被回收后内存可用的时间。 

    依赖于不同的场景,对于GC的性能指标的关注点也不一样。 

    分代GC 
    分代GC把内存划分为多个代(内存区域),每个代存储不同年龄的对象。 常见的分为2代,young和old。 
    分配内存时,先从young代分配,如果young代已满,可以执行GC(可能导致对象提升),如果有空间,则分配,如果young代还是没有空间,可以对整个内存堆GC。 
    young代GC后还存活的对象可以提升到old代。 
    该机制基于以下观察事实: 
    1 大部分新分配的对象很快就没有引用了,变成垃圾。 
    2 很少有old代对象引用young代对象。 
    基于代内存存储对象的特性,对不同代的内存可以使用不同的GC算法。 
    Young代GC需要高效,快速,频繁的执行,关注点主要在速度上。 
    Old代由于增长缓慢,因此GC不频繁,但是其内存空间比较大,因此,需要更长时间才能执行完GC。关注点在内存空间利用率上。 

     



    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 代上)。 

     


    快速内存分配 
    大部分的内存分配请求发生时,Collector都有一块大的连续内存块,简单的内存大小计算和指针移动就可以分配内存了。因此非常快速。该技术称为bump –the-pointer技术。 

    对于多线程的内存分配,每个线程使用Thread Local Allocation Buffer(TLAB)进行分配,因此还是很高效。TLAB可以看作一个线程的特殊代。只有TLAB满的时候才需要进行同步操作。 

    GC根集合 
    GC运行时当前程序可以直接访问的对象。如线程中当前调用栈的方法参数,局部变量,静态变量,当前线程对象等等。 
    Collector根据GC根集合来寻找所有活对象。GC根集合不可达对象自然就是垃圾了。 


    Serial Collector 
    单线程,Young and old GC是串行,stop the world GC的。 
    Young GC。 
    Eden中活对象copy到to survivor中,大对象直接进old代。 
    From survivor中相对老的活对象进入old代,相对年轻的对象进入to survivor中。 
    如果to survivor放不下活对象,则这些活对象直接进入old。 
    经历过young GC,Eden和from survivor都变成空的内存区域,to survivor存储有活的对象。To survivor和from survivor角色互换。 

    Old permanent GC。 
    Mark-sweep-compact算法。 
    S1 标识哪些对象是活的对象。 
    S2 标识哪些对象是垃圾。 
    S3 把活的对象压缩到内存的一端,以便可以使用bump –the-pointer处理以后的内存分配请求。 

    非server-class machine 的默认GC。 
    也可以使用命令行参数来设定。 
    -XX:+UseSerialGC 


    Parallel Collector/Throughput Collector 
    利用了现代计算机大部分都是多核的事实。 
    Young GC。 
    和Serial Collector一样,是一个stop the world和copying Collector。只不过是多线程并行扫描和做copy,提高速度,减少了stop the world的时间,增大了throughput。 
    Old permanent GC。 
    和serial collector一样。Mark-sweep-compact算法。单线程。 

    Server-class machine的默认GC。 
    也可以使用命令行参数来设定。 
    -XX:+UseParallelGC 

    Parallel Compacting Collector 
    Young GC。 
    和Parallel Collector一样。 
    Old Permanent GC。 
    Stop the world,并且多线程并发GC。 
    每一代被划分为一些长度固定的区域。 
    第1步(mark phase),GC根集合划分后分发给多个GC线程,每个GC线程更新可达活对象所在区域的信息(活对象的内存位置,大小)。 
    第2步(summary phase),操作在区域上,而不是对象上。由于以前GC的影响,内存的一端活对象的密度比较高,在该阶段找到一个临界点,该临界点以前的区域由于活对象内存密度高,不参与GC,不做compact。该临界点之后的区域参与GC,做compact。该阶段为单线程执行。 
    第3步(compact phase)。GC多线程使用summary info做回收和compact工作。 

    可以设置GC线程数,防止GC线程长时间占有整台机器的资源。 
    -XX:ParallelGCThreads=n 
    使用命令行参数来设定。 
    -XX:+UseParallelOldGC 


    Concurrent Mark Sweep Collector (CMS)
     
    Young GC。 
    和Parallel Collector一样。 
    Old permanent GC。 
    GC和程序并发执行。 
    Initial Phase:短暂停,标记GC根集合。单线程执行。 
    Concurrent marking phase: GC多线程标记从根集合可达的所有活对象。程序和GC并发运行。由于是并发运行,有可能有活对象没有被标记上。 
    concurrent pre-clean:单线程,并发执行。 
    Remark phase: 短暂停,多线程标记在Concurrent marking phase中有变化的相关对象。 
    Concurrent sweep phase:和程序并发执行。单线程执行。不做compacting。 
    concurrent reset:单线程,并发执行。 

    CMS不做compacting,不能使用bump-the-pointer技术,只能使用传统的内存空闲链表技术。 
    导致内存分配变慢,影响了Young代的GC速度,因为Young的GC如果有对象提升的话依赖于Old的内存分配。 
    CMS需要更多的内存空间,因为mark phase时程序还是在运行,程序可以申请更多的old空间。在mark phase中,CMS保证标识活对象,但是该过程中,活对象可能转变为垃圾,只能等待下一次GC才能回收。 

    和其他Collector不同,CMS不是等到old满时才GC,基于以前的统计数据(GC时间,Old空间消耗速度)来决定何时GC。CMS GC也可以基于old空间的占用率。 
    命令行参数: 
    -XX:CMSInitiatingOccupancyFraction=n,n为百分比,默认68。 
    可以设置 
    -XX:+UseCMSInitiatingOccupancyOnly 来使vm只使用old内存占用比来触发CMS GC。 

    Incremental Mode。 
    CMS的concurrent phase可以是渐进式执行。以减少程序的一次暂停时间。 

    命令行参数: 
    -XX:+UseConcMarkSweepGC 
    -XX:+CMSIncrementalMode 

    4种Collector的对比和适用场景。 
    直到jdk1.3.1,java只提供Serial Collector,Serial Collector在多核的机器上表现比较差。主要是throughput比较差。 
    大型应用(大内存,多核)应该选用并行Collector。 
    Serial Collector:大多数client-style机器。对于低程序暂停时间没有需求的程序。 
    Parallel Collector:多核机器,对于低程序暂停时间没有需求的程序。 
    Parallel Compacting Collector:多核机器,对于低程序暂停时间有需求的程序。 
    CMS Collector:和Parallel Compacting Collector相比,降低了程序暂停时间,但是young GC程序暂停时间变长,需要更大的堆空间,降低了程序的throughput。 

    Ergonomics 
    J2SE 5.0后,Collector的选择,堆大小的选择,VM(client还是server)的选择,都可以依赖平台和OS来做自动选择。 

    JVM会自动选择使用server mode还是client mode。但是我们一样可以手工设置。 
    java -server -client 

    Server-class machine的选择: 
    2个或更多的处理器  
    And 
    2G或更多的物理内存 
    And 
    不是32bits,windows OS。 

    Client-class 
    The client JVM 
    The serial collector 
    Initial heap size = 4M 
    Max heap size=64M 

    Server-class 
    The server JVM 
    The parallel collector 
    Initial heap size= 1/64物理内存(>=32M),最大1G。 
    Max heap size=1/4物理内存,最大1G。 


    基于行为的调优。 

    可以基于最大暂停时间或throughput。 

    -XX:MaxGCPauseMillis=n 
    指示vm调整堆大小和其他参数来满足这个时间需求。如果vm不满足该目标,则减小堆大小来满足该目标。该目标没有默认值。 

    -XX:GCTimeRatio=n 
    GC time/APP time=1/(1+n) 
    如n=99表示GC时间占整个运行时间的1%。 
    如果该目标不能满足,则增大堆大小来满足该目标。默认值n=99。 

    Footprint Goal 
    如果最大暂停时间和Throughput目标都满足了,则减少堆大小直到有一个目标不满足,然后又回调。 

    目标优先级: 
    最大暂停时间>Throughput>footprint。 

    GC调优 
    由于有了Ergonomics,第一个建议就是不要手工去配置各种参数。让系统自己去根据平台和OS来选择。然后观测性能,如果OK的话,呵呵,不用搞了。 

    但是Ergonomics也不是万能的。因此还是需要程序员来手工搞。 
    注意性能问题一定要测量/调优/测量/调优不停的循环下去。 

    Vm mode 选择。 
    Java -server server mode. 
    Java -client client mode. 


    观测性能主要使用gc的统计信息。 
    -XX:+PrintGC 输出GC信息。 
    -XX:+PrintGCDetails输出GC详细信息。 
    -XX:+PrintGCTimeStamps 输出时间戳,和–XX:+PrintGC 或–XX:+PrintGCDetails一起使用。 
    -Xloggc: gc.log 输出到指定文件。 


    1 决定堆内存大小。 
    决定整个堆内存的大小。内存的大小对于Collector的性能影响是最大的。 

    使用以下参数来决定堆内存的大小。 
    可以决定堆空间的起始值和最大值,大型程序可以考虑把起始值调大,避免程序启动时频繁GC和内存扩展申请。 
    以及堆空间中可用内存的比例范围,vm会动态管理堆内存来满足该比例范围。 
    -XX:MinHeapFreeRatio=n 
    -XX:MaxHeapFreeRatio=n 
    -Xmsn Young和Old的起始内存 
    -Xmxn Young和Old的最大内存 

    2 决定代空间大小。 
    Young代空间越大,则minor GC的频率越小。但是,给定堆内存大小,Young代空间大,则major GC频率变大。 
    如果没有过多的Full GC或者过长的暂停时间问题,给young代尽量大的空间。 

    Young Generation Guarantee。 
    对于serial collector,当执行minor GC时,必须保证old代中有可用的空间来处理最坏情况(即eden和survivor空间中的对象都是活对象,需要提升至old空间),如果不满足,则该minor GC触发major GC。所以对于serial collector,设置eden+survivor的内存不要大过old代内存。 
    其他collector不做该保证,只有old代无法存储提升对象时才触发major GC。 

    对于其他collector,由于多线程做minor GC时,考虑到最坏情况,每个线程要在old代内存预留一定空间做对象提升,因此可能导致内存碎片。因此old代内存应该调整的更大一些。 

    -XX:NewSize=n young代空间下限。 
    -XX:MaxNewSize=n young代空间上限。 
    -XX:NewRatio=n young和old代的比例。 
    -XX:SurvivorRatio=n Eden和单个survivor的比例。 

    -XX:PermSize=n Permanent起始值。 
    -XX:MaxPermSize=n Permanent最大值。 

    3 决定使用Collector 
    可以考虑是否需要换一个Collector。 
    Collector选择 
    -XX:+UseSerialGC Serial 
    -XX:+UseParallelGC Parallel 
    -XX:+UseParallelOldGC Parallel compacting 
    -XX:+UseConcMarkSweepGC Concurrent mark–sweep (CMS) 

    Parallel和Parallel Compacting Collector. 
    -XX:ParallelGCThreads=n 
    -XX:MaxGCPauseMillis=n 
    -XX:GCTimeRatio=n 
    设定目标好于明确设定参数值。 

    为了增大Throughput,堆大小需要变大。可以把堆大小设为物理内存允许的最大值(同时程序不swapping)来检测该环境可以支持的最大throughput。 
    为了减小最大暂停时间和footprint,堆大小需要变小。 
    2个目标有一定的矛盾,因此要视具体应用场景,做平衡。 

    CMS Collector 
    -XX:+CMSIncrementalMode 和CMS同时使用。 
    -XX:+CMSIncrementalPacing 和CMS同时使用。 
    -XX:ParallelGCThreads=n 
    -XX:CMSInitiatingOccupancyFraction=n,n为百分比,默认68。 


    OutOfMemoryError 
    可以指定 
    -XX:+HeapDumpOnOutOfMemoryError 
    当发生OutOfMemoryError时dump出堆内存。 

    发生OutOfMemoryError时可以观测该Error的详细信息。 

    Java heap space: 
    调整堆大小。 
    程序中含有大量带有finalize方法的对象。执行finalize方法的线程顶不住了。 
    PermGen space: 
    Permanent代内存不够用了。 
    Requested array size exceeds VM limit。 
    堆内存不够用。 
    程序bug,一次分配太多内存。 


    freeMemory(),totalMemory(),maxMemory() 
    java.lang.Runtime类中的 freeMemory(), totalMemory(), maxMemory()这几个方法的反映的都是 java这个进程的内存情况,跟操作系统的内存根本没有关系。 

    maxMemory()这个方法返回的是java虚拟机(这个进程)能构从操作系统那里挖到的最大的内存,以字节为单位,如果在运行java程序的时 候,没有添加-Xmx参数,那么就是jvm默认的可以使用内存大小,client为64M,server为1G。如果添加了-Xmx参数,将以这个参数后面的值为准。 

    totalMemory()这个方法返回的是java虚拟机现在已经从操作系统那里挖过来的内存大小,也就是java虚拟机这个进程当时所占用的所有内存。如果在运行java的时候没有添加-Xms参数,那么,在java程序运行的过程的,内存总是慢慢的从操作系统那里挖的,基本上是用多少挖多少,直 到挖到maxMemory()为止,所以totalMemory()是慢慢增大的。如果用了-Xms参数,程序在启动的时候就会无条件的从操作系统中挖 -Xms后面定义的内存数,然后在这些内存用的差不多的时候,再去挖。 

    freeMemory()是什么呢,刚才讲到如果在运行java的时候没有添加-Xms参数,那么,在java程序运行的过程的,内存总是慢慢的从操 作系统那里挖的,基本上是用多少挖多少,但是java虚拟机100%的情况下是会稍微多挖一点的,这些挖过来而又没有用上的内存,实际上就是 freeMemory(),所以freeMemory()的值一般情况下都是很小的,但是如果你在运行java程序的时候使用了-Xms,这个时候因为程 序在启动的时候就会无条件的从操作系统中挖-Xms后面定义的内存数,这个时候,挖过来的内存可能大部分没用上,所以这个时候freeMemory()可能会有些大。 


    jmap工具的使用
     
    jmap pid 查看共享对象。 
    jmap -heap pid 查看java进程堆的相关信息。 

    Java代码  收藏代码
    1. $ jmap -heap 5695  
    2. Attaching to process ID 5695, please wait...  
    3. Debugger attached successfully.  
    4. Server compiler detected.  
    5. JVM version is 17.0-b16  
    6.   
    7. using parallel threads in the new generation.  
    8. using thread-local object allocation.  
    9. Concurrent Mark-Sweep GC  
    10.   
    11. Heap Configuration:  
    12.    MinHeapFreeRatio = 40  
    13.    MaxHeapFreeRatio = 70  
    14.    MaxHeapSize      = 1342177280 (1280.0MB)  
    15.    NewSize          = 134217728 (128.0MB)  
    16.    MaxNewSize       = 134217728 (128.0MB)  
    17.    OldSize          = 4194304 (4.0MB)  
    18.    NewRatio         = 2  
    19.    SurvivorRatio    = 20000  
    20.    PermSize         = 100663296 (96.0MB)  
    21.    MaxPermSize      = 134217728 (128.0MB)  
    22.   
    23. Heap Usage:  
    24. New Generation (Eden + 1 Survivor Space):  
    25.    capacity = 134152192 (127.9375MB)  
    26.    used     = 34518744 (32.919639587402344MB)  
    27.    free     = 99633448 (95.01786041259766MB)  
    28.    25.731032408326207% used  
    29. Eden Space:  
    30.    capacity = 134086656 (127.875MB)  
    31.    used     = 34518744 (32.919639587402344MB)  
    32.    free     = 99567912 (94.95536041259766MB)  
    33.    25.743608670500368% used  
    34. From Space:  
    35.    capacity = 65536 (0.0625MB)  
    36.    used     = 0 (0.0MB)  
    37.    free     = 65536 (0.0625MB)  
    38.    0.0% used  
    39. To Space:  
    40.    capacity = 65536 (0.0625MB)  
    41.    used     = 0 (0.0MB)  
    42.    free     = 65536 (0.0625MB)  
    43.    0.0% used  
    44. concurrent mark-sweep generation:  
    45.    capacity = 671088640 (640.0MB)  
    46.    used     = 287118912 (273.81793212890625MB)  
    47.    free     = 383969728 (366.18206787109375MB)  
    48.    42.7840518951416% used  
    49. Perm Generation:  
    50.    capacity = 100663296 (96.0MB)  
    51.    used     = 41864504 (39.92510223388672MB)  
    52.    free     = 58798792 (56.07489776611328MB)  
    53.    41.58864816029867% used  

    jmap –histo pid 查询各种对象占用的内存大小。 
    Java代码  收藏代码
    1. $ jmap -histo 5695 | less  
    2.   
    3.  num     #instances         #bytes  class name  
    4. ----------------------------------------------  
    5.    1:        320290       63305456  [C  
    6.    2:       1457010       46624320  java.util.concurrent.ConcurrentHashMap$Segment  
    7.    3:       1502500       36060000  java.util.concurrent.locks.ReentrantLock$NonfairSync  
    8.    4:         87785       29987632  [I  
    9.    5:       1457010       23638928  [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;  
    10.    6:        285668       15240784  [Ljava.lang.Object;  
    11.    7:         87239       10680160  <constMethodKlass>  
    12.    8:        399482        9587568  java.lang.String  
    13.    9:         16533        7466624  [B  
    14.   10:         91065        7285072  [Ljava.util.concurrent.ConcurrentHashMap$Segment;  
    15.   11:         87239        6983288  <methodKlass>  
    16.   12:        125750        5868720  <symbolKlass>  
    17.   13:         45409        5449080  java.net.SocksSocketImpl  
    18.   14:         63574        4936176  [S  
    19.   15:         45294        4710576  sun.nio.ch.SocketChannelImpl  


    jmap –permstat pid 查看Class Loader。 

    jmap –dump:file=filename,format=b pid dump内存到文件。 

    可以使用MAT工具分析java dump文件。 
    展开全文
  • 简介:FullGC与MinorGC讲解 Minor GC触发条件 当Eden区满时,触发Minor GC FullGC触发条件 ...因此强烈建议能不使⽤此⽅法就不要使⽤,让虚拟机⾃⼰去管理它的内存。可通过 -XX:+ DisableExplicitGC 来禁⽌ ...
    简介:FullGC与MinorGC讲解
    Minor GC触发条件

    当Eden区满时,触发Minor GC

    FullGC触发条件
    • 调⽤ System.gc() 此⽅法的调⽤是建议 JVM 进⾏ Full GC,虽然只是建议⽽⾮⼀定,但很多情况下它会触发 Full GC。因此强烈建议能不使⽤此⽅法就不要使⽤,让虚拟机⾃⼰去管理它的内存。可通过 -XX:+ DisableExplicitGC 来禁⽌ RMI 调⽤ System.gc()
    • ⽼年代空间不⾜ ⽼年代空间不⾜的常⻅场景为前⽂所讲的⼤对象直接进⼊⽼年代、⻓期存活的对象进⼊⽼年代等,当执⾏ Full GC 后空间仍然不⾜,则抛出Java.lang.OutOfMemoryError。为避免以上原因引起的 Full GC,调优时应尽量做到让对象在 Minor GC 阶段被回收、让对象在新⽣代多存活⼀段时间以及不要创建过⼤的对象及数组
    • 空间分配担保失败 使⽤复制算法的 Minor GC 需要⽼年代的内存空间作担保,如果出现HandlePromotionFailure 担保失败,则会触发 Full GC
    项⽬中出现频繁FullGC,也就是系统空间分配不⾜导致的系统堆内存强制回收
    • 由于本机单服务内存过⼤导致,此场景下Full GC,⽽且需要回收的内存很⼤,持续时间过⻓
    • 解决停顿时间过⻓问题,缩短GC时间
    展开全文
  • 前言近期被问及这个问题,在此记录整理一下。System.gc()方法的调用此...强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。老年代...

    前言

    近期被问及这个问题,在此记录整理一下。

    System.gc()方法的调用

    此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。

    老年代空间不足

    老年代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出如下错误:

    java.lang.OutOfMemoryError: Java heap space

    为避免以上两种状况引起的Full GC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。

    永生区空间不足

    JVM规范中运行时数据区域中的方法区,在HotSpot虚拟机中又被习惯称为永生代或者永生区,Permanet Generation中存放的为一些class的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下也会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出如下错误信息:

    java.lang.OutOfMemoryError: PermGen space

    为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC。

    CMS GC时出现promotion failed和concurrent mode failure

    对于采用CMS进行老年代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure两种状况,当这两种状况出现时可能

    会触发Full GC。

    promotion failed是在进行Minor GC时,survivor space放不下、对象只能放入老年代,而此时老年代也放不下造成的;concurrent mode failure是在

    执行CMS GC的过程中同时有对象要放入老年代,而此时老年代空间不足造成的(有时候“空间不足”是CMS GC时当前的浮动垃圾过多导致暂时性的空间不足触发Full GC)。

    对措施为:增大survivor space、老年代空间或调低触发并发GC的比率,但在JDK 5.0+、6.0+的版本中有可能会由于JDK的bug29导致CMS在remark完毕

    后很久才触发sweeping动作。对于这种状况,可通过设置-XX: CMSMaxAbortablePrecleanTime=5(单位为ms)来避免。

    统计得到的Minor GC晋升到旧生代的平均大小大于老年代的剩余空间

    这是一个较为复杂的触发情况,Hotspot为了避免由于新生代对象晋升到旧生代导致旧生代空间不足的现象,在进行Minor GC时,做了一个判断,如果之

    前统计所得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间,那么就直接触发Full GC。

    例如程序第一次触发Minor GC后,有6MB的对象晋升到旧生代,那么当下一次Minor GC发生时,首先检查旧生代的剩余空间是否大于6MB,如果小于6MB,

    则执行Full GC。

    当新生代采用PS GC时,方式稍有不同,PS GC是在Minor GC后也会检查,例如上面的例子中第一次Minor GC后,PS GC会检查此时旧生代的剩余空间是否

    大于6MB,如小于,则触发对旧生代的回收。

    除了以上4种状况外,对于使用RMI来进行RPC或管理的Sun JDK应用而言,默认情况下会一小时执行一次Full GC。可通过在启动时通过- java -

    Dsun.rmi.dgc.client.gcInterval=3600000来设置Full GC执行的间隔时间或通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。

    堆中分配很大的对象

    所谓大对象,是指需要大量连续内存空间的java对象,例如很长的数组,此种对象会直接进入老年代,而老年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象,此种情况就会触发JVM进行Full GC。

    为了解决这个问题,CMS垃圾收集器提供了一个可配置的参数,即-XX:+UseCMSCompactAtFullCollection开关参数,用于在“享受”完Full GC服务之后额外免费赠送一个碎片整理的过程,内存整理的过程无法并发的,空间碎片问题没有了,但提顿时间不得不变长了,JVM设计者们还提供了另外一个参数 -XX:CMSFullGCsBeforeCompaction,这个参数用于设置在执行多少次不压缩的Full GC后,跟着来一次带压缩的。

    展开全文
  • 前言近期被问及这个问题,在此记录整理一下。System.gc()方法的调用此...强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。老年代...

    前言

    近期被问及这个问题,在此记录整理一下。

    System.gc()方法的调用

    此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。

    老年代空间不足

    老年代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出如下错误:

    java.lang.OutOfMemoryError: Java heap space

    为避免以上两种状况引起的Full GC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。

    永生区空间不足

    JVM规范中运行时数据区域中的方法区,在HotSpot虚拟机中又被习惯称为永生代或者永生区,Permanet Generation中存放的为一些class的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下也会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出如下错误信息:

    java.lang.OutOfMemoryError: PermGen space

    为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC。

    CMS GC时出现promotion failed和concurrent mode failure

    对于采用CMS进行老年代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure两种状况,当这两种状况出现时可能

    会触发Full GC。

    promotion failed是在进行Minor GC时,survivor space放不下、对象只能放入老年代,而此时老年代也放不下造成的;concurrent mode failure是在

    执行CMS GC的过程中同时有对象要放入老年代,而此时老年代空间不足造成的(有时候“空间不足”是CMS GC时当前的浮动垃圾过多导致暂时性的空间不足触发Full GC)。

    对措施为:增大survivor space、老年代空间或调低触发并发GC的比率,但在JDK 5.0+、6.0+的版本中有可能会由于JDK的bug29导致CMS在remark完毕

    后很久才触发sweeping动作。对于这种状况,可通过设置-XX: CMSMaxAbortablePrecleanTime=5(单位为ms)来避免。

    统计得到的Minor GC晋升到旧生代的平均大小大于老年代的剩余空间

    这是一个较为复杂的触发情况,Hotspot为了避免由于新生代对象晋升到旧生代导致旧生代空间不足的现象,在进行Minor GC时,做了一个判断,如果之

    前统计所得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间,那么就直接触发Full GC。

    例如程序第一次触发Minor GC后,有6MB的对象晋升到旧生代,那么当下一次Minor GC发生时,首先检查旧生代的剩余空间是否大于6MB,如果小于6MB,

    则执行Full GC。

    当新生代采用PS GC时,方式稍有不同,PS GC是在Minor GC后也会检查,例如上面的例子中第一次Minor GC后,PS GC会检查此时旧生代的剩余空间是否

    大于6MB,如小于,则触发对旧生代的回收。

    除了以上4种状况外,对于使用RMI来进行RPC或管理的Sun JDK应用而言,默认情况下会一小时执行一次Full GC。可通过在启动时通过- java -

    Dsun.rmi.dgc.client.gcInterval=3600000来设置Full GC执行的间隔时间或通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。

    堆中分配很大的对象

    所谓大对象,是指需要大量连续内存空间的java对象,例如很长的数组,此种对象会直接进入老年代,而老年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象,此种情况就会触发JVM进行Full GC。

    为了解决这个问题,CMS垃圾收集器提供了一个可配置的参数,即-XX:+UseCMSCompactAtFullCollection开关参数,用于在“享受”完Full GC服务之后额外免费赠送一个碎片整理的过程,内存整理的过程无法并发的,空间碎片问题没有了,但提顿时间不得不变长了,JVM设计者们还提供了另外一个参数 -XX:CMSFullGCsBeforeCompaction,这个参数用于设置在执行多少次不压缩的Full GC后,跟着来一次带压缩的。

    展开全文
  • 一、JVM创建新对象的内存分配过程 以下是JVM中创建一个新...强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。 2.2 老年代空间不足 老年
  • JVM何时会进行全局GC

    2017-12-02 17:52:55
    1、System.gc()方法的调用此方法的...强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。2、老年代代空间不足老年代空间只有在新生代对象
  • 最近很多人找我要GC Server...首先,你需要一个支持C/C++的IDE(强烈推荐Visual Studio,后面的操作会更方便),然后你需要下载一个图形库,比如WinAPI。最后你需要将图形库安装到你的IDE的配置里面,将include和lib都
  • Full GC触发的几个场景

    2019-05-17 11:42:02
    1、System.gc()方法的调用 此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率...强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可...
  • 1、System.gc()方法的调用   此方法的调用是建议JVM...强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。 2、老年代代空间不
  • 1、System.gc()方法的调用   此方法的调用是建议JVM...强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。 2、老年代代空间不足
  • 强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。 老年代空间不足 老年代空间只有在新生代对象转入及创建为大对象、大数组时才会...
  • Python 为了实现 GC,在 Object 头部增加了两个额外的指针,Python 作为一种高级语言,对 “Object” 有着强烈的执念,同时也造成内存效率较低,现在又新增了两个指针,真可谓是 “儿到荒年饭量增,屋漏偏逢连夜雨”...
  • 再谈之前 先给大家强烈推荐一本书。《分布式Java应用》 作者 林昊 它里面很清楚写了相关 java 底层基础相关知识。 本人根据书里面的讲解的内容以及各大博客学习的心得 将其整理一下。如果有不足之处的请各位大神...
  • JVM会自己选择合适的垃圾收集策略,而用户也可以自己来设置所需要的垃圾收集策略,但是就个人而言,强烈建议采用默认的垃圾收集处理机制。 垃圾的收集一定要分两个空间考虑:年轻代、老年代。老年代的内存空间要...
  • https://www.cnblogs.com/penghongwei/p/3603326.html https://blog.csdn.net/renfufei/article/details/77585294 ...虽然加大内存可以暂时解决这个问题,但是还是强烈建议去优化代码,后者更加有效。 ...
  • 视频推荐JVM合集 | 从零开始的JVM、GC基础知识、GC算法、JVM的垃圾回收器、面试JVM实战、 实战调优 1:什么是JVM JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个...
  • 阿里面试题目目录 技术一面(基础面试题目) 技术二面(技术深度、技术原理) 项目实战(项目模拟面试) ... gc原理 hashmap listlink arraylist 区别 aop 原理 多线程 kafka 原理和容错 .
  • 内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例所持有却不再被使用导致 GC 不能回收。既然说到内存泄漏和优化,就不得不先简单了解一下内存分配策略,然后再举常见泄漏...
  • 深入浅出JVM之总结

    2019-07-30 23:51:06
    传统项目有可能遇到的Jvm问题:服务单点故障,下载功能遇到问题 Minor GC触发条件:当Eden区满时,触发Minor GC ...因此,强烈建议能不使用此方法就不要使用,让虚拟机自己去管理内存。可通过-XX:+DisableExp...
  • 在典型的GC虚拟机中,对象在不再被(强烈)引用之后很长一段时间内可能会继续存在于内存中,但是使用弱引用缓存,我们允许GC收集此类数据,但是缓存可以返回此数据直到将其垃圾回收为止,以确保更有效地使用内存。...
  • 不过在此之前强烈建议先看这篇文章深度揭秘垃圾回收底层。因为这篇文章解释了很多有关垃圾回收的基本知识,能从源头上理解垃圾回收和日益发展的垃圾收集器演进的方向,这很重要。本文章所说的 GC 实现没有特殊说明的...
  • jdk-10_linux-x64_bin.tar.gz

    2018-03-21 15:22:05
    Java SE 10 is the latest release of Java SE Platform. This release contains improvements like Local-Variable Type Inference, Parallel Full GC, Application ... Oracle强烈建议所有Java SE用户升级到此版本。
  • jdk-10_windows-x64_bin.exe

    2018-03-21 12:04:08
    Java SE 10 is the latest release of Java SE Platform. This release contains improvements like Local-Variable Type Inference, Parallel Full GC, Application ... Oracle强烈建议所有Java SE用户升级到此版本。
  • jdk-10_osx-x64_bin.dmg

    2018-03-21 12:09:46
    Java SE 10 is the latest release of Java SE Platform. This release contains improvements like Local-Variable Type Inference, Parallel Full GC, Application ... Oracle强烈建议所有Java SE用户升级到此版本。
  • 非常实用的图层管理工具,一直在用,非常右手,加载后运行gc显示物体所在图层,按kc显示所有关闭的图层,非常方便,强烈推荐!
  • 内存泄漏的检测

    2017-11-23 15:18:18
    3、LeakCanary 强烈推荐: Android Studio和MAT结合使用来分析内存问题new Thread() :每次进入界面都会创建实例,并且不会被GC 非静态内存类的静态变量:只在第一次进入界面创建实例,并且不会被GC
  • 不过在此之前强烈建议先看这篇文章深度揭秘垃圾回收底层。 因为这篇文章解释了很多有关垃圾回收的基本知识,能从源头上理解垃圾回收和日益发展的垃圾收集器演进的方向,这很重要。 本文章所说的 GC 实现没有特殊...
  • 首先,希望大家强烈认识到Silverlight程序是托管的,除特别明显或强烈的需要外(例如OpenFileDialog、SaveFileDialog等继承自IDisposable接口的类),望大家不要轻易介入GC.Collect(),这是微软设计.NET的初衷,我

空空如也

空空如也

1 2 3
收藏数 58
精华内容 23
关键字:

强烈gc