Java深入 - Java 内存分配和回收机制

时间:2022-12-10 08:19:03

Java的GC机制是自动进行的,和c语言有些区别需要程序员自己保证内存的使用和回收。

Java的内存分配和回收也主要在Java的堆上进行的,Java的堆中存储了大量的对象实例,所以Java的堆也叫GC堆。

Java在垃圾收集的过程中,主要用到了分代收集算法,我会先讲一下常用垃圾收集算法。

常用垃圾收集算法

1. 标记-清除算法

这种垃圾收集算法思路非常简单,主要是首先标记出所有需要回收的对象,然后回收所有需要回收的对象。

但是有一个明显的缺点,采用这种算法之后会发现内存块回收之后就不连续了,这就导致了在下一次想分配一个大内存块的时候无法分配。

Java深入 - Java 内存分配和回收机制

2. 标记-清除-压缩

这种垃圾收集算法主要是对上面的算法进行了优化,内存回收了对内存进行了一次优化压缩。这样回收后内存块的连续性又比较强了。

但是这种算法会涉及到不停的内存间的拷贝和复制,性能会非常差。

Java深入 - Java 内存分配和回收机制

3.标记-清除-复制

这种算法会将内存空间分配成两块相同的区域A和B。当内存回收的时候,将A中的内存块拷贝到B中,然后一次性清空A。

但是这种算法会对内存要求比较大一些,并且长期复制拷贝性能上也会受影响。

Java深入 - Java 内存分配和回收机制

Java分代收集算法

Java主要采用了分代收集算法。分代收集算法主要将对象存活期的长短将内存进行划分。

Java主要将内存划分为两部分:新生代老生代

Java的新生代中,对象的存活率低,存活期期会相对会比较短一些,所以可以选用复制算法来进行内存回收。

Java的老生代中,对象的存活率比较高,并且相对存活期比较长一些,可以采用标记-清除-压缩的算法来进行内存回收。

可以看图:

Java深入 - Java 内存分配和回收机制

通常新生代分为Eden和两个Survivor,其中可以通过-XX:SurvivorRatio=1来设置(这里要考虑两个Survivor,意味着二个S的大小是整个新生代的2/3)

前面已经说了,Java的内存分配和内存回收主要在Java的堆上进行的。而Java的方法区间和常量池我们一般称为永久代。永久代可以通过-XX:PermSize=512M -XX:MaxPermSize=512M设置

Java堆内存设置参数:-Xmx20m -Xms20m

Java堆新生代内存分配设置:-Xmn10m 新生代分配了10M的内存,那么剩下的10M就是老生代上面分配了。也可以设置:-XX:NewRatio=4

通过设置参数,我们就可以在控制台中看到Java虚拟机在执行GC时候的日志:-XX:+PrintGCDetails  

也可以指定日志的位置:-Xloggc:gc.log  

永久代一般是指方法区和常量池,一般情况下永久代在虚拟机运行时就能确定大小的,但是一些框架可能动态生成一些类信息就会导致永久代越来越大。

Java内存分配策略

使用的ParNew+Serial Old收集器组合

1. 优先在Eden上分配。

Java的对象优先会在新生代的Eden上分配。

我们可以看一个例子:

我设置了这些参数:-XX:+PrintGCDetails -Xms20m -Xmx20m -Xmn10m,堆内存分配20M,新生代10M,老生代10M,默认情况下Survivor区为8:1,所以Eden区域为8M

我运行这段代码:

  1. public class JavaTest {
  2. static int m = 1024 * 1024;
  3. public static void main(String[] args) {
  4. //分配2兆
  5. byte[] a1 = new byte[2 * m];
  6. System.out.println("a1 ok");
  7. //分配2兆
  8. byte[] a2 = new byte[2 * m];
  9. System.out.println("a2 ok");
  10. }
  11. }

控制台日志:

  1. a1 ok
  2. a2 ok
  3. Heap
  4. def new generation   total 9216K, used 4603K [0x331d0000, 0x33bd0000, 0x33bd0000)
  5. eden space 8192K,  56% used [0x331d0000, 0x3364ef50, 0x339d0000)
  6. from space 1024K,   0% used [0x339d0000, 0x339d0000, 0x33ad0000)
  7. to   space 1024K,   0% used [0x33ad0000, 0x33ad0000, 0x33bd0000)
  8. tenured generation   total 10240K, used 0K [0x33bd0000, 0x345d0000, 0x345d0000)
  9. the space 10240K,   0% used [0x33bd0000, 0x33bd0000, 0x33bd0200, 0x345d0000)
  10. compacting perm gen  total 12288K, used 381K [0x345d0000, 0x351d0000, 0x385d0000)
  11. the space 12288K,   3% used [0x345d0000, 0x3462f4d0, 0x3462f600, 0x351d0000)
  12. ro space 10240K,  55% used [0x385d0000, 0x38b51140, 0x38b51200, 0x38fd0000)
  13. rw space 12288K,  55% used [0x38fd0000, 0x396744c8, 0x39674600, 0x39bd0000)

日志中非常清晰的可以看到,我们分配了一个4M内存大小,直接是分配在了eden space里面。

2. 大对象直接进入老生代。

参数:-XX:PretenureSizeThreshold(该设置只对Serial和ParNew收集器生效) 可以设置进入老生代的大小限制,我们设置为3M,则大于3M的大对象就直接进入老生代

测试代码:

  1. public class JavaTest {
  2. static int m = 1024 * 1024;
  3. public static void main(String[] args) {
  4. //分配2兆
  5. byte[] a1 = new byte[2 * m];
  6. System.out.println("a1 ok");
  7. byte[] a3 = new byte[4 * m];
  8. System.out.println("a2 ok");
  9. }
  10. }

控制台日志:

  1. a1 ok
  2. a2 ok
  3. Heap
  4. def new generation   total 9216K, used 2555K [0x331d0000, 0x33bd0000, 0x33bd0000)
  5. eden space 8192K,  31% used [0x331d0000, 0x3344ef40, 0x339d0000)
  6. from space 1024K,   0% used [0x339d0000, 0x339d0000, 0x33ad0000)
  7. to   space 1024K,   0% used [0x33ad0000, 0x33ad0000, 0x33bd0000)
  8. tenured generation   total 10240K, used 4096K [0x33bd0000, 0x345d0000, 0x345d0000)
  9. the space 10240K,  40% used [0x33bd0000, 0x33fd0010, 0x33fd0200, 0x345d0000)
  10. compacting perm gen  total 12288K, used 381K [0x345d0000, 0x351d0000, 0x385d0000)
  11. the space 12288K,   3% used [0x345d0000, 0x3462f4d0, 0x3462f600, 0x351d0000)
  12. ro space 10240K,  55% used [0x385d0000, 0x38b51140, 0x38b51200, 0x38fd0000)
  13. rw space 12288K,  55% used [0x38fd0000, 0x396744c8, 0x39674600, 0x39bd0000)

上面的日志中,可以清洗看到第一次分配的2M留存在了eden space中,而4M超过了大对象设置的值3M,所以直接进入了老生代tenured generation

3. 长期存活的对象进入老年代

为了演示方便,我们设置-XX:MaxTenuringThreshold=1(默认15),当在新生代中年龄为1的对象进入老年代。

测试代码:

  1. public class JavaTest {
  2. static int m = 1024 * 1024;
  3. public static void main(String[] args) {
  4. //分配2兆
  5. byte[] a1 = new byte[1 * m / 4];
  6. System.out.println("a1 ok");
  7. byte[] a2 = new byte[7 * m];
  8. System.out.println("a2 ok");
  9. byte[] a3 = new byte[3 * m]; //GC
  10. System.out.println("a3 ok");
  11. }
  12. }

控制台日志:

  1. a1 ok
  2. a2 ok
  3. [GC [DefNew: 7767K->403K(9216K), 0.0062209 secs] 7767K->7571K(19456K), 0.0062482 secs]
  4. [Times: user=0.00 sys=0.00, real=0.01 secs]
  5. a3 ok
  6. Heap
  7. def new generation   total 9216K, used 3639K [0x331d0000, 0x33bd0000, 0x33bd0000)
  8. eden space 8192K,  39% used [0x331d0000, 0x334f9040, 0x339d0000)
  9. from space 1024K,  39% used [0x33ad0000, 0x33b34de8, 0x33bd0000)
  10. to   space 1024K,   0% used [0x339d0000, 0x339d0000, 0x33ad0000)
  11. tenured generation   total 10240K, used 7168K [0x33bd0000, 0x345d0000, 0x345d0000)
  12. the space 10240K,  70% used [0x33bd0000, 0x342d0010, 0x342d0200, 0x345d0000)
  13. compacting perm gen  total 12288K, used 381K [0x345d0000, 0x351d0000, 0x385d0000)
  14. the space 12288K,   3% used [0x345d0000, 0x3462f548, 0x3462f600, 0x351d0000)
  15. ro space 10240K,  55% used [0x385d0000, 0x38b51140, 0x38b51200, 0x38fd0000)
  16. rw space 12288K,  55% used [0x38fd0000, 0x396744c8, 0x39674600, 0x39bd0000)

我们可以看到在A3处有一次GC,并且a2的7M已经满足-XX:MaxTenuringThreshold=1的要求,所以a2进入老年代,而空出来的空间a3就进入新生代

4. 动态对象年龄判定

为了使内存分配更加灵活,虚拟机并不要求对象年龄达到MaxTenuringThreshold才晋升老年代

如果Survivor区中相同年龄所有对象大小的总和大于Survivor区空间的一半,年龄大于或等于该年龄的对象在Minor GC时将复制至老年代

5. 空间分配担保

新生代使用复制算法,当Minor GC时如果存活对象过多,无法完全放入Survivor区,就会向老年代借用内存存放对象,以完成Minor GC。

在触发Minor GC时,虚拟机会先检测之前GC时租借的老年代内存的平均大小是否大于老年代的剩余内存,如果大于,则将Minor
GC变为一次Full GC,如果小于,则查看虚拟机是否允许担保失败,如果允许担保失败,则只执行一次Minor GC,否则也要将Minor
GC变为一次Full GC。

说白了,新生代放不下就会借用老年代的空间来进行GC

Java垃圾收集器:

首先我们可以看一张图,下面这张图中列出来新生代和老生代可以用到的垃圾收集器。

Java深入 - Java 内存分配和回收机制

1. Serial 收集器 串行

单线程的串行收集器。它在垃圾收集的时候会暂停其它所有工作线程。直到收集结束。一般在客户端模式下使用。

2. ParNew收集器 并行

ParNew收集器是Serial的多线程版本。一般运行在Server模式下首先的新生代收集器。如果老年代使用CMS收集器,基本也只能和它进行合作。参数:-XX:+UseConcMarkSweepGC,比较适合web服务的收集器。

一般ParNew和CMS组合

3. Parallel Scavenge收集器 并行

它使用复制算法的收集器,并且是多线程的。该收集器主要目的就是达到一个可控制的吞吐量,说白了就是CPU的利用率。于是该收集器比较适合后端运算比较多的服务。

-XX:MaxGCPauseMillis每次年轻代垃圾回收的最长时间(最大暂停时间),收集器尽量保证内存回收时间不大于这个值,应该设置一个合理的值。

-XX:GCTimeRatio设置垃圾回收时间占程序运行时间的百分比

-XX:+UseAdaptiveSizePolicy 设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开.

4.Serial Old收集器 串行

单线程串行的老生代收集器。

5. Parallel Old 收集器 并行

使用“标记-整理”的算法。该收集器比较适合和Parallel Scavenge收集器进行组合。-XX:+UseParallelOldGC

6. CMS收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,目前大部分的B/S系统都使用CMS的收集器。一般CMS是老生代收集器,新生代就和PerNew进行组合。

CMS收集器基于“标记-清除”的算法。分四个阶段:初始标记,并发标记,重新标记,并发清除

CMS收集器的优点:并发收集、低停顿

CMS缺点:

1. CMS收集器对CPU资源非常敏感。在并发阶段,虽然不会导致用户线程停顿,但是会占用CPU资源而导致引用程序变慢,总吞吐量下降。CMS默认启动的回收线程数是:(CPU数量+3) / 4。

2. 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”失败,性能反而降低。

3. CMS是基于“标记-清除”算法实现的收集器,使用“标记-清除”算法收集后,会产生大量碎片。空间碎片太多时,将会给对象分配带来很多麻烦,比如说大对象,内存空间找不到连续的空间来分配不得不提前触发一次Full  GC。为了解决这个问题,CMS收集器提供了一个-XX:UseCMSCompactAtFullCollection开关参数,用于在Full  GC之后增加一个碎片整理过程,还可通过-XX:CMSFullGCBeforeCompaction参数设置执行多少次不压缩的Full
 GC之后,跟着来一次碎片整理过程。

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 Parallel 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

附表:

参数名称 含义 默认值  
-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  
-Xss 每个线程的堆栈大小   JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行 调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右
一般小的应用, 如果栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。(校长)
和threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:"”
-Xss is translated in a VM flag named ThreadStackSize”
一般设置这个值就可以了。
-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.]
-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 锁机制的性能改善    
-Xnoclassgc 禁用垃圾回收    
-XX:SoftRefLRUPolicyMSPerMB 每兆堆空闲空间中SoftReference的存活时间 1s softly reachable objects will remain alive
for some amount of time after the last time they were referenced. The
default value is one second of lifetime per free megabyte in the heap
-XX:PretenureSizeThreshold 对象超过多大是直接在旧生代分配 0 单位字节 新生代采用Parallel Scavenge GC时无效
另一种直接在旧生代分配的情况是大的数组对象,且数组中无外部引用对象.
-XX:TLABWasteTargetPercent TLAB占eden区的百分比 1%  
-XX:+CollectGen0First FullGC时是否先YGC false  

并行收集器相关参数

-XX:+UseParallelGC Full GC采用parallel MSC
(此项待验证)
 

选择垃圾收集器为并行收集器.此配置仅对年轻代有效.即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集.(此项待验证)

-XX:+UseParNewGC 设置年轻代为并行收集   可与CMS收集同时使用
JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值
-XX:ParallelGCThreads 并行收集器的线程数   此值最好配置与处理器数目相等 同样适用于CMS
-XX:+UseParallelOldGC 年老代垃圾收集方式为并行收集(Parallel Compacting)   这个是JAVA 6出现的参数选项
-XX:MaxGCPauseMillis 每次年轻代垃圾回收的最长时间(最大暂停时间)   如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值.
-XX:+UseAdaptiveSizePolicy 自动选择年轻代区大小和相应的Survivor区比例   设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开.
-XX:GCTimeRatio 设置垃圾回收时间占程序运行时间的百分比   公式为1/(1+n)
-XX:+ScavengeBeforeFullGC Full GC前调用YGC true Do young generation GC prior to a full GC. (Introduced in 1.4.1.)

CMS相关参数

-XX:+UseConcMarkSweepGC 使用CMS内存收集   测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明.所以,此时年轻代大小最好用-Xmn设置.???
-XX:+AggressiveHeap     试图是使用大量的物理内存
长时间大内存使用的优化,能检查计算资源(内存, 处理器数量)
至少需要256MB内存
大量的CPU/内存, (在1.4.1在4CPU的机器上已经显示有提升)
-XX:CMSFullGCsBeforeCompaction 多少次后进行内存压缩   由于并发收集器不对内存空间进行压缩,整理,所以运行一段时间以后会产生"碎片",使得运行效率降低.此值设置运行多少次GC以后对内存空间进行压缩,整理.
-XX:+CMSParallelRemarkEnabled 降低标记停顿    
-XX+UseCMSCompactAtFullCollection 在FULL GC的时候, 对年老代的压缩   CMS是不会移动内存的, 因此, 这个非常容易产生碎片, 导致内存不够用, 因此, 内存的压缩这个时候就会被启用。 增加这个参数是个好习惯。
可能会影响性能,但是可以消除碎片
-XX:+UseCMSInitiatingOccupancyOnly 使用手动定义初始化定义开始CMS收集   禁止hostspot自行触发CMS GC
-XX:CMSInitiatingOccupancyFraction=70 使用cms作为垃圾回收
使用70%后开始CMS收集
92 为了保证不出现promotion failed(见下面介绍)错误,该值的设置需要满足以下公式CMSInitiatingOccupancyFraction计算公式
-XX:CMSInitiatingPermOccupancyFraction 设置Perm Gen使用到达多少比率时触发 92  
-XX:+CMSIncrementalMode 设置为增量模式   用于单CPU情况
-XX:+CMSClassUnloadingEnabled      

辅助信息

-XX:+PrintGC    

输出形式:

[GC 118250K->113543K(130112K), 0.0094143 secs]
[Full GC 121376K->10414K(130112K), 0.0650971 secs]

-XX:+PrintGCDetails    

输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]
[GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured:
112761K->10414K(121024K), 0.0433488 secs]
121376K->10414K(130112K), 0.0436268 secs]

-XX:+PrintGCTimeStamps      
-XX:+PrintGC:PrintGCTimeStamps     可与-XX:+PrintGC -XX:+PrintGCDetails混合使用
输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
-XX:+PrintGCApplicationStoppedTime 打印垃圾回收期间程序暂停的时间.可与上面混合使用   输出形式:Total time for which application threads were stopped: 0.0468229 seconds
-XX:+PrintGCApplicationConcurrentTime 打印每次垃圾回收前,程序未中断的执行时间.可与上面混合使用   输出形式:Application time: 0.5291524 seconds
-XX:+PrintHeapAtGC 打印GC前后的详细堆栈信息    
-Xloggc:filename 把相关日志信息记录到文件以便分析.
与上面几个配合使用
   

-XX:+PrintClassHistogram

garbage collects before printing the histogram.    
-XX:+PrintTLAB 查看TLAB空间的使用情况    
XX:+PrintTenuringDistribution 查看每次minor GC后新的存活周期的阈值  

Desired survivor size 1048576 bytes, new threshold 7 (max 15)
new threshold 7即标识新的存活周期的阈值为7。

Java深入 - Java 内存分配和回收机制的更多相关文章

  1. Java基础-Java中的内存分配与回收机制

    Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二.

  2. java虚拟机的内存分配与回收机制

    分为4个方面来介绍内存分配与回收,分别是内存是如何分配的.哪些内存需要回收.在什么情况下执行回收.如何监控和优化GC机制. java GC(Garbage Collction)垃圾回收机制,是java ...

  3. Java深入 - Java 内存分配和回收机制-转

    Java的GC机制是自动进行的,和c语言有些区别需要程序员自己保证内存的使用和回收. Java的内存分配和回收也主要在Java的堆上进行的,Java的堆中存储了大量的对象实例,所以Java的堆也叫GC ...

  4. JAVA虚拟机内存分配与回收机制

    Java虚拟机(Java Virtual Machine) 简称JVM Java虚拟机是一个想象中的机器,在实际的计算机上通过软件模拟来实现.Java虚拟机有自己想象中的硬件,如处理器.堆栈.寄存器等 ...

  5. 【java虚拟机】内存分配与回收策略

    作者:平凡希 原文地址:https://www.cnblogs.com/xiaoxi/p/6557473.html 前言 对象的内存分配,往大的方向上讲,就是在堆上分配,少数情况下也可能会直接分配在老 ...

  6. 转!!Java虚拟机堆的内存分配和回收

    Java内存分配和回收,主要就是指java堆的内存分配和回收.java堆一般分为2个大的区域,一块是新生代,一块是老年代.在新生代中又划分了3块区域,一块eden区域,两块surviver区域.一般称 ...

  7. memcached内存分配及回收初探

    对memcached(后面简称mc) 的内存分配及回收机制进行了深度分析和测试,以下是一些学习的心得,和大家共同探讨一下,期望能抛砖引玉 mc简介: mc是由LiveJournal技术团队开发的一套分 ...

  8. Java虚拟机垃圾回收:内存分配与回收策略 方法区垃圾回收 以及 JVM垃圾回收的调优方法

    在<Java对象在Java虚拟机中的创建过程>了解到对象创建的内存分配,在<Java内存区域 JVM运行时数据区>中了解到各数据区有些什么特点.以及相关参数的调整,在<J ...

  9. Java 对象内存分配与回收

    JVM内存区域模型: * 程序计数器,内存区域极小,是当前线程的字节码执行行号指示器: * 虚拟机栈.本地方法栈,即平时所说的“栈”,是虚拟机用来执行方法(包括Java.非Java方法)时,使用的临时 ...

随机推荐

  1. AngularJS 第三天----作用域

    作用域的概念及其功能 AngularJS使用作用域的概念来充当数据模型的作用,在视图和控制器之间起着桥梁的作用.由于双向绑定的数据特性,视图的修改会更新 $scope,同样对 $scope的修改也会重 ...

  2. blue and red ball

    #include<iostream> #include<cstring> using namespace std; int sum; ]; int n; int head; i ...

  3. &lt&semi;context&colon;component-scan&gt&semi;使用说明

    Spring组件扫描<context:component-scan/>使用详解 在xml配置了这个标签后,spring可以自动去扫描base-pack下面或者子包下面的java文件,如果扫 ...

  4. android中图片的三级缓存cache策略&lpar;内存&sol;文件&sol;网络&rpar;

    实现图片缓存也不难,需要有相应的cache策略.这里我采用 内存-文件-网络 三层cache机制,其中内存缓存包括强引用缓存和软引用缓存(SoftReference),其实网络不算cache,这里姑且 ...

  5. SQLServer 数据导入导出 SSIS 包 位置

    笔记:sqlserver 在执行数据导入导出的时候,可以选择是否保存SSIS包,如果选择保存,在保存方式有:SQlserver .文件系统.如果选择sqlserver 则 包信息保存在 msdb 系统 ...

  6. bzoj3668&colon; &lbrack;Noi2014&rsqb;起床困难综合症

    从高位到低位枚举期望的应该是ans最高位尽量取一.如果该数最高位为o的话能够取得1直接更新ans否则判断该位取1是否会爆m不会的话就加上. #include<cstdio> #includ ...

  7. WPF 判断是否为设计&lpar;Design&rpar;状态

    在WinForm开发中,一般会在窗体或者UserControl中判断当前是否为设计状态,如: if (!this.DesignMode) {     // } 有时候需要在Load事件中加上一些从服务 ...

  8. linux命令行执行db2存储过程

    存储过程代码如下: CREATE PROCEDURE proc_sum2(IN n INT,OUT sum INT,OUT j INT) BEGIN DECLARE i INT; ; ; ; WHIL ...

  9. (转载)MVC 4&period;0 PartialView&lpar;&rpar;与View&lpar;&rpar;真的一样吗?

    转载自:http://www.cnblogs.com/lori/ 当我们使用razor作为页面引擎时,它的视图文件扩展名为cshtml或者vbshtml,而之前作为分部视图的ascx文件,进行razo ...

  10. CSS3实现图片鼠标悬浮放大效果

    .excerpt .focus a img{ -webkit-transition: all ease .3s; transition: all ease .3s }.excerpt .focus a ...