小结:

  • 新生代    串行Serial            并行 Parallel(关注吞吐量)           并行ParNew
  • 老年代    串行 Serial Old     并行Parallel Old(关注吞吐量)     并发CMS(关注停顿时间)
  • 新生代:复制算法             老年代 :标记-整理算法(CMS:标记-清除,可以设置参数设置在每次Full GC  后者几次Full GC后进行内存碎片的压缩整理)
  • G1收集器基于标记-整理算法实现,也就是说不会产生内存碎片。G1收集器进行收集的范围是个Java(包括新生代,老年代)
  • 吞吐量:运行代码时间/(运行代码时间+GC收集时间)。GC时间缩短是以牺牲吞吐量和新生代空间来获取的:系统把新生代调小一些,导致垃圾收集发生得更频繁一些,这样停顿时间的确下降了,但是吞吐量也下降了。

上面有7中收集器,分为两块,上面为新生代收集器,下面是老年代收集器。如果两个收集器之间存在连线,就说明它们可以搭配使用。

1, 串行回收器

1.1, 新生代串行回收器Serial

(1)特点: 
  –它仅仅使用单线程进行垃圾回收 
  –它是独占式的垃圾回收 
  –进行垃圾回收时, Java应用程序中的线程都需要暂停(Stop-The-World) 
  –使用复制算法 
  –适合CPU等硬件不是很好的场合 
(2)设置参数: 
  -XX:+UseSerialGC 指定新生使用新生代串行收集器和老年代串行收集器, 当以client模式运行时, 它是默认的垃圾收集器

1.2, 老年代串行回收器Serial Old

(1)特点: 
  –同新生代串行回收器一样, 单线程, 独占式的垃圾回收器 使用标记-整理算法
  –通常老年代垃圾回收比新生代回收要更长时间, 所以可能会使应用程序停顿较长时间

(2)设置参数: 
  -XX:+UseSerialGC 新生代, 老年代都使用串行回收器 
  -XX:+UseParNeGC 新生代使用ParNew回收器, 老年代使用串行回收器 
  -XX:+UseParallelGC 新生代使用ParallelGC回收器, 老年代使用串行回收器


2, 并行回收器

2.1, 新生代ParNew回收器

(1)特点: 
  –将串行回收多线程化, 
  –使用复制算法 
  –垃圾回收时, 应用程序仍会暂停, 只不过由于是多线程回收, 在多核CPU上,回收效率会高于串行回收器, 反之在单核CPU, 效率会不如串行回收器 
(2)设置参数: 
  -XX:+UseParNewGC 新生代使用ParNew回收器, 老年代使用串行回收器 
  -XX:+UseConcMarkSweepGC 新生代使用ParNew回收器, 老年代使用CMS回收器 
  -XX:ParallelGCThreads=n 指回ParNew回收器工作时的线程数量, cpu核数小时8时, 其值等于cpu数量, 高于8时,可以使用公式(3+((5*CPU_count)/8))

2.2, 新生代Parallel回收器

(1)特点: 
  –同ParNew回收器一样, 不同的地方在于,它非常关注系统的吞吐量(通过参数控制) 
  –使用复制算法 
  –支持自适应的GC调节策略

(3)设置参数:

  -XX:+UseParallelGC  新生代用ParallelGC回收器, 老年代使用串行回收器 
  -XX:+UseParallelOldGC  新生代用ParallelGC回收器, 老年代使用ParallelOldGC回收器系统吞吐量的控制: 
  -XX:MaxGCPauseMillis=n(单位ms)   设置垃圾回收的最大停顿时间, 
  -XX:GCTimeRatio=n(n在0-100之间)  设置吞吐量的大小, 假设值为n, 那系统将花费不超过1/(n+1)的时间用于垃圾回收 
  -XX:+UseAdaptiveSizePolicy  打开自适应GC策略, 在这种模式下, 新生代的大小, eden,survivior的比例, 晋升老年代的对象年龄等参数会被自动调整,以达到堆大小, 吞吐量, 停顿时间之间的平衡点

2.3, 老年代Parallel Old回收器

(1)特点: 
  –同新生代的ParallelGC回收器一样, 是属于老年代的关注吞吐量的多线程并发回收器 
  –使用标记压缩算法, 
(2)设置参数: 
  -XX:+UseParallelOldGC  新生代用ParallelGC回收器, 老年代使用ParallelOldGC回收器, 是非常关注系统吞吐量的回收器组合, 适合用于对吞吐量要求较高的系统 
  -XX:ParallelGCThreads=n   指回ParNew回收器工作时的线程数量, cpu核数小时8时, 其值等于cpu数量, 高于8时, 可以使用公式(3+((5*CPU_count)/8))


3, 老年代CMS回收器(Concurrent Mark Sweep,并发、标记清除)

3.1, 老年代的并发回收器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。CMS收集器是基于“标记-清除”算法实现的,整个收集过程大致分为4个步骤:

①.初始标记(CMS initial mark)

②.并发标记(CMS concurrenr mark)

③.重新标记(CMS remark)

④.并发清除(CMS concurrent sweep)

     其中初始标记、重新标记这两个步骤任然需要停顿其他用户线程。初始标记仅仅只是标记出GC ROOTS能直接关联到的对象,速度很快,并发标记阶段是进行GC ROOTS 根搜索算法阶段,会判定对象是否存活。而重新标记阶段则是为了修正并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间会被初始标记阶段稍长,但比并发标记阶段要短。
     由于整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,所以整体来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。
CMS收集器的优点:并发收集、低停顿,但是CMS还远远达不到完美,器主要有三个显著缺点:
CMS收集器对CPU资源非常敏感。在并发阶段,虽然不会导致用户线程停顿,但是会占用CPU资源而导致引用程序变慢,总吞吐量下降。CMS默认启动的回收线程数是:(CPU数量+3) / 4。
CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure“,失败后而导致另一次Full  GC的产生。由于CMS并发清理阶段用户线程还在运行,伴随程序的运行自热会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在本次收集中处理它们,只好留待下一次GC时将其清理掉。这一部分垃圾称为“浮动垃圾”。也是由于在垃圾收集阶段用户线程还需要运行,
即需要预留足够的内存空间给用户线程使用,因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分内存空间提供并发收集时的程序运作使用。在默认设置下,CMS收集器在老年代使用了68%的空间时就会被激活,也可以通过参数-XX:CMSInitiatingOccupancyFraction的值来提供触发百分比,以降低内存回收次数提高性能。要是CMS运行期间预留的内存无法满足程序其他线程需要,就会出现“Concurrent Mode Failure”失败,这时候虚拟机将启动后备预案:临时启用Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了。所以说参数-XX:CMSInitiatingOccupancyFraction设置的过高将会很容易导致“Concurrent Mode Failure”失败,性能反而降低。
最后一个缺点,CMS是基于“标记-清除”算法实现的收集器,使用“标记-清除”算法收集后,会产生大量碎片。空间碎片太多时,将会给对象分配带来很多麻烦,比如说大对象,内存空间找不到连续的空间来分配不得不提前触发一次Full  GC。为了解决这个问题,CMS收集器提供了一个-XX:UseCMSCompactAtFullCollection开关参数,用于在Full  GC之后增加一个碎片整理过程,还可通过-XX:CMSFullGCBeforeCompaction参数设置执行多少次不压缩的Full  GC之后,跟着来一次碎片整理过程。

(1)特点: 
  –是并发回收, 非独占式的回收器, 大部分时候应用程序不会停止运行 
  –针对年老代的回收器, 
  –使用并发标记清除算法, 因此回收后会有内存碎片, 可以使参数设置进行内存碎片的压缩整理 
  –ParallelGC和ParallelOldGC主要关注吞吐量, CMS主要关注系统停顿时间 
(2)CMS主要步骤: 
  1. 初始标记 
  2. 并发标记 
  3. 重新标记 
  4. 并发清除

–>注:初始标记与重新标记是独占系统资源的,不能与用户线程一起执行,而其它阶段则可以与用户线程一起执行 
(3)设置参数: 
  -XX:-CMSPrecleaningEnabled  关闭预清理, 不进行预清理, 默认在并发标记后, 会有一个预清理的操作,可减少停顿时间 
  -XX:+UseConcMarkSweepGC  老年代使用CMS回收器, 新生代使用ParNew回收器 
  -XX:ConcGCThreads=n  设置并发线程数量, 
  -XX:ParallelCMSThreads=n  同上, 设置并发线程数量, 
  -XX:CMSInitiatingOccupancyFraction=n  指定老年代回收阀值, 即当老年代内存使用率达到这个值时, 会执行一次CMS回收,默认值为68, 设置技巧: (Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100)>=Xmn 
  -XX:+UseCMSCompactAtFullCollection  开启内存碎片的整理, 即当CMS垃圾回收完成后, 进行一次内存碎片整理, 要注意内存碎片的整理并不是并发进行的, 因此可能会引起程序停顿 
  -XX:CMSFullGCsBeforeCompation=n  用于指定进行多少次CMS回收后, 再进行一次内存压缩 
  -XX:+CMSParallelRemarkEnabled  在使用UseParNewGC 的情况下, 尽量减少 mark 的时间 
  -XX:+UseCMSInitiatingOccupancyOnly  表示只有达到阀值时才进行CMS回收

3.2, Class的回收(永久区的回收)

设置参数: 
  -XX:+CMSClassUnloadingEnabled  开启回收Perm区的内存, 默认情况下, 是需要触发一次FullGC 
  -XX:CMSInitiatingPermOccupancyFraction=n  当永久区占用率达到这个n值时,启动CMS回收, 需上一个参数开启的情况下使用


4, G1回收器(jdk1.7后全新的回收器, 用于取代CMS)

  G1(Garbage First)收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。还有一个特点之前的收集器进行收集的范围都是整个新生代或老年代,而G1将整个Java堆(包括新生代,老年代)。

(1)特点: 
  –独特的垃圾回收策略, 属于分代垃圾回收器, 
  –使用分区算法, 不要求eden, 年轻代或老年代的空间都连续 
  –并行性: 回收期间, 可由多个线程同时工作, 有效利用多核cpu资源 
  –并发性: 与应用程序可交替执行, 部分工作可以和应用程序同时执行, 
  –分代GC: 分代收集器, 同时兼顾年轻代和老年代 
  –空间整理: 回收过程中, 会进行适当对象移动, 减少空间碎片 
  –可预见性: G1可选取部分区域进行回收, 可以缩小回收范围, 减少全局停顿 
(2)G1的收集过程 
1. 新生代GC: 
2. 并发标记周期: 
  –初始标记新生代GC(此时是并行, 应用程序会暂停止)–>根区域扫描–>并发标记–>重新标记(此时是并行, 应用程序会暂停止)–>独占清理(此时应用程序会暂停止)–>并发清理 
3. 混合回收: 
  –这个阶段即会执行正常的年轻代gc, 也会选取一些被标记的老年代区域进行回收, 同时处理新生代和年老轻 
4. 若需要, 会进行FullGC: 
  –混合GC时发生空间不足 
  –在新生代GC时, survivor区和老年代无法容纳幸存对象时, 
  –以上两者都会导致一次FullGC产生 
(3)设置参数: 
  -XX:+UseG1GC  打开G1收集器开关, 
  -XX:MaxGCPauseMillis=n  指定目标的最大停顿时间,任何一次停顿时间超过这个值, G1就会尝试调整新生代和老年代的比例, 调整堆大小, 调整晋升年龄 
  -XX:ParallelGCThreads=n  用于设置并行回收时, GC的工作线程数量 
  -XX:InitiatingHeapOccpancyPercent=n  指定整个堆的使用率达到多少时, 执行一次并发标记周期, 默认45, 过大会导致并发标记周期迟迟不能启动, 增加FullGC的可能, 过小会导致GC频繁, 会导致应用程序性能有所下降


5, 其他GC相关的设置

5.1, System.gc()

(1)禁用System.gc() 
  -XX:+DisableExplicitGC  禁止程序中调用System.gc(), 加了此参数, 程序若有调用, 返回的空函数调用 
   System.gc()的调用, 会使用FullGC的方式回收整个堆而会忽略CMS或G1等相关回收器 
(2)System.gc()使用并发回收 
  -XX:+ExplicitGCCinvokesConcurrent   使用并发方式处理显示的gc, 即开启后, System.gc()这种显示GC才会并发的回收, (CMS, G1)

5.2, 并行GC前额外触发的新生代GC

(1)使用并行回收器(UseParallelGC或者UseParallelOldGC)时, 会额外先触发一个新生代GC, 目的是尽可能减少停顿时间 
(2)若不需要这种特性, 可以使用以下参数去除 
  -XX:-ScavengeBeforeFullGC   即去除在FullGC之前的那次新生代GC, 原本默认值为true 
  

5.3, 对象何时进入老年代

(1)当对象首次创建时, 会放在新生代的eden区, 若没有GC的介入,会一直在eden区, GC后,是可能进入survivor区或者年老代 
(2)当对象年龄达到一定的大小 ,就会离开年轻代, 进入老年代, 对象进入老年代的事件称为晋升, 而对象的年龄是由GC的次数决定的, 每一次GC,若对象没有被回收, 则对象的年龄就会加1, 可以使用以下参数来控制新生代对象的最大年龄: 
  -XX:MaxTenuringThreshold=n  假设值为n , 则新生代的对象最多经历n次GC, 就能晋升到老年代, 但这个必不是晋升的必要条件 
  -XX:TargetSurvivorRatio=n  用于设置Survivor区的目标使用率,即当survivor区GC后使用率超过这个值, 就可能会使用较小的年龄作为晋升年龄 
(3)除年龄外, 对象体积也会影响对象的晋升的, 若对象体积太大, 新生代无法容纳这个对象, 则这个对象可能就会直接晋升至老年代, 可通过以下参数使用对象直接晋升至老年代的阈值, 单位是byte 
  -XX:PretenureSizeThreshold  即对象的大小大于此值, 就会绕过新生代, 直接在老年代分配, 此参数只对串行回收器以及ParNew回收有效, 而对ParallelGC回收器无效,

5.4, 在TLAB上分配对象(Thread Local Allocation Buffer, 线程本地分配缓存)

(1)TLAB: TLAB是一个线程专用的内存分配区域, 虚拟机为线程分配空间, 针对于体积不大的对象, 会优先使用TLAB, 这个可以加速对象的分配, TLAB是默认开启的, 若要关闭可以使用以下参数关闭 
  -XX:-UseTLAB  关闭TLAB 
  -XX:+UseTLAB  开启TLAB, 默认也是开启的 
  -XX:+PrintTLAB  观察TALB的使用情况 
  -XX:TLABRefillWasteFraction=n  设置一个比率n, 而refill_waste的值就是(TLAB_SIZE/n), 即TLAB空间较小, 大对象无法分配在TLAB,所以会直接分配到堆上,TLAB较小也很容易装满, 因此当TLAB的空间不够分配一个新对象, 就会考虑废弃当前TLAB空间还是直接分配到堆上, 就会使用此参数进行判断, 小于refill_waste就允许废弃, 而新建TLAB来分配对象,而大于refill_waste就直接在堆上分配, 默认是64 
  -XX:+ResizeTLAB  开启TLAB自动调整大小, 默认是开启的, 若要关闭把+号换成-号即可 
  -XX:TLABSize=n  设置一个TLAB的大小, 前提先关闭TLAB的自动调整

垃圾收集器参数总结

-XX:+<option> 启用选项
-XX:-<option> 不启用选项
-XX:<option>=<number> 
-XX:<option>=<string>
参数 描述

-XX:+UseSerialGC

Jvm运行在Client模式下的默认值,打开此开关后,使用Serial + Serial Old的收集器组合进行内存回收
-XX:+UseParNewGC 打开此开关后,使用ParNew + Serial Old的收集器进行垃圾回收
-XX:+UseConcMarkSweepGC 使用ParNew + CMS +  Serial Old的收集器组合进行内存回收,Serial Old作为CMS出现“Concurrent Mode Failure”失败后的后备收集器使用。
-XX:+UseParallelGC Jvm运行在Server模式下的默认值,打开此开关后,使用Parallel Scavenge +  Serial Old的收集器组合进行回收
-XX:+UseParallelOldGC 使用Parallel Scavenge +  Parallel Old的收集器组合进行回收
-XX:SurvivorRatio 新生代中Eden区域与Survivor区域的容量比值,默认为8,代表Eden:Subrvivor = 8:1
-XX:PretenureSizeThreshold 直接晋升到老年代对象的大小,设置这个参数后,大于这个参数的对象将直接在老年代分配
-XX:MaxTenuringThreshold 晋升到老年代的对象年龄,每次Minor GC之后,年龄就加1,当超过这个参数的值时进入老年代
-XX:UseAdaptiveSizePolicy 动态调整java堆中各个区域的大小以及进入老年代的年龄
-XX:+HandlePromotionFailure 是否允许新生代收集担保,进行一次minor gc后, 另一块Survivor空间不足时,将直接会在老年代中保留
-XX:ParallelGCThreads 设置并行GC进行内存回收的线程数
-XX:GCTimeRatio GC时间占总时间的比列,默认值为99,即允许1%的GC时间,仅在使用Parallel Scavenge 收集器时有效
-XX:MaxGCPauseMillis 设置GC的最大停顿时间,在Parallel Scavenge 收集器下有效
-XX:CMSInitiatingOccupancyFraction 设置CMS收集器在老年代空间被使用多少后出发垃圾收集,默认值为68%,仅在CMS收集器时有效,-XX:CMSInitiatingOccupancyFraction=70
-XX:+UseCMSCompactAtFullCollection 由于CMS收集器会产生碎片,此参数设置在垃圾收集器后是否需要一次内存碎片整理过程,仅在CMS收集器时有效
-XX:+CMSFullGCBeforeCompaction 设置CMS收集器在进行若干次垃圾收集后再进行一次内存碎片整理过程,通常与UseCMSCompactAtFullCollection参数一起使用
-XX:+UseFastAccessorMethods 原始类型优化
-XX:+DisableExplicitGC 是否关闭手动System.gc
-XX:+CMSParallelRemarkEnabled 降低标记停顿
-XX:LargePageSizeInBytes 内存页的大小不可设置过大,会影响Perm的大小,-XX:LargePageSizeInBytes=128m

Client、Server模式默认GC

  新生代GC方式 老年代和持久GC方式

Client

Serial 串行GC Serial Old 串行GC
Server Parallel Scavenge  并行回收GC Parallel Old 并行GC

Sun/oracle JDK GC组合方式

 
 
  新生代GC方式 老年代和持久GC方式

-XX:+UseSerialGC

Serial 串行GC Serial Old 串行GC
-XX:+UseParallelGC Parallel Scavenge  并行回收GC Serial Old  并行GC
-XX:+UseConcMarkSweepGC ParNew 并行GC CMS 并发GC 
当出现“Concurrent Mode Failure”时
采用Serial Old 串行GC
-XX:+UseParNewGC ParNew 并行GC Serial Old 串行GC
-XX:+UseParallelOldGC Parallel Scavenge  并行回收GC Parallel Old 并行GC
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
Serial 串行GC CMS 并发GC 
当出现“Concurrent Mode Failure”时
采用Serial Old 串行GC

转自  http://blog.csdn.net/lghuntfor/article/details/51052737

http://blog.csdn.net/java2000_wl/article/details/8030172

JVM 垃圾回收器详解的更多相关文章

  1. 深入理解JVM虚拟机3:垃圾回收器详解

    JVM GC基本原理与GC算法 Java的内存分配与回收全部由JVM垃圾回收进程自动完成.与C语言不同,Java开发者不需要自己编写代码实现垃圾回收.这是Java深受大家欢迎的众多特性之一,能够帮助程 ...

  2. JVM垃圾回收详解

    通常,我们在写java程序的时候,似乎很少关注内存分配和垃圾回收的问题.因为,这部分工作,JVM已经帮我们自动实现了. 这样看起来,好像很美好,但是任何事情都有两面性.虽然JVM会自动的进行垃圾回收, ...

  3. JVM 的垃圾回收器详解

    Parallel Scavenge(Paraller):Parallel Scavenge和ParNew关注的点不一样:ParNew关注的是尽可能缩短暂停的时间,Parallel Scavenge关注 ...

  4. JVM垃圾回收算法及回收器详解

    引言 本文主要讲述JVM中几种常见的垃圾回收算法和相关的垃圾回收器,以及常见的和GC相关的性能调优参数. GC Roots 我们先来了解一下在Java中是如何判断一个对象的生死的,有些语言比如Pyth ...

  5. Java虚拟机之垃圾回收详解一

    Java虚拟机之垃圾回收详解一 Java技术和JVM(Java虚拟机) 一.Java技术概述: Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布.它是Java程序的技术基础,这 ...

  6. JVM 垃圾回收器工作原理及使用实例介绍(转载自IBM),直接复制粘贴,需要原文戳链接

    原文 https://www.ibm.com/developerworks/cn/java/j-lo-JVMGarbageCollection/ 再插一个关于线程和进程上下文,待判断 http://b ...

  7. Jvm垃圾回收器(终结篇)

    知识回顾: 第一篇<Jvm垃圾回收器(基础篇)>主要讲述了判断对象的生死?两种基础判断对象生死的算法.引用计数法.可达性分析算法,方法区的回收.在第二篇<Jvm垃圾回收器(算法篇)& ...

  8. JVM基础系列第9讲:JVM垃圾回收器

    前面文章中,我们介绍了 Java 虚拟机的内存结构,Java 虚拟机的垃圾回收机制,那么这篇文章我们说说具体执行垃圾回收的垃圾回收器. 总的来说,Java 虚拟机的垃圾回收器可以分为四大类别:串行回收 ...

  9. Jvm垃圾回收器(算法篇)

    在<Jvm垃圾回收器(基础篇)>中我们主要学习了判断对象是否存活还是死亡?两种基础的垃圾回收算法:引用计数法.可达性分析算法.以及Java引用的4种分类:强引用.软引用.弱引用.虚引用.和 ...

随机推荐

  1. BNUOJ 33898 Cannon

    Cannon Time Limit: 1000ms Memory Limit: 65535KB This problem will be judged on HDU. Original ID: 449 ...

  2. RabbitMQ-linux安装rabbitmq(二)

    说明 本地装了个虚拟机模拟集群 所以记下安装步骤 安装Erlang 安装类库 yum -y install ncurses-devel yum -y install openssl-devel yum ...

  3. MTK平台系统稳定性分析

    目录 1:简介 2:怎么抓取和分析log 3:怎么确定问题点 简介 系统稳定性目前主要是解决系统死机重启. 分为两部分:Android /kernel Kernel 分析需要的文件和工具: Mtklo ...

  4. Linux基本命令总结(初学者可以借鉴学习)

    Linux基本常用命令 个人在平时项目中用到的一些常规命令总结下 删除文件夹命令:rm -rf 目录名字 添加模式:按i 退出编辑模式:ese左上角键 首先先按esc退出进入一个模式然后再输入wq或者 ...

  5. 函数操作(this操作)

    1.apply/call函数:会改变this关键字,并且第一个参数作为this关键字. /*apply与call区别*/ console.log(Array.prototype.join.call([ ...

  6. UVa 12279 - Emoogle Balance

    题目:给你n个数字推断.零和非零数字的个数差. 分析:简单题. 读入数据非零+1.为零-1. 说明:目标650题╮(╯▽╰)╭. #include <iostream> #include ...

  7. shell 例程 —— 解决redis读取稳定性

    问题背景: php读取线上redis数据,常常不稳定,数据响应时有时无. 解决方法:多次读取.每次读取全部上一次没读出的数据,直到全部获取. 本文实现用shell进行多次redis数据读取, 每次取出 ...

  8. 【ubuntu firefox】 Firefox is already running, but is not responding

    在ubuntu下启动firefox报错 Firefox is already running, but is not responding. To open a new window, you mus ...

  9. TGraphicControl和TCustomControl自绘过程的理论解释

    TGraphicControl = class(TControl) // 这个类实在是简单,因为所有事情都已经委托给它的父Win控件了,只要管自己即可 private FCanvas: TCanvas ...

  10. git分支的合并和冲突解决【转】

    本文转载自:http://blog.csdn.net/Kingson_Wu/article/details/39227611 http://gitbook.liuhui998.com/3_3.html ...