堆内存使用分析,GC 日志解读

重要的东东

  • 在Java中,对象实例都是在堆上创建。一些类信息,常量,静态变量等存储在方法区。堆和方法区都是线程共享的。
  • GC机制是由JVM提供,用来清理需要清除的对象,回收堆内存。
  • GC机制将Java程序员从内存管理中解放了出来,可以更关注于业务逻辑。
  • 在Java中,GC是由一个被称为垃圾回收器的守护线程执行的。
  • 在从内存回收一个对象之前会调用对象的finalize()方法。
  • 作为一个Java开发者不能强制JVM执行GC;GC的触发由JVM依据堆内存的大小来决定。
  • System.gc()和Runtime.gc()会向JVM发送执行GC的请求,但是JVM不保证一定会执行GC。
  • 如果堆没有内存创建新的对象了,会抛出OutOfMemoryError。

什么样的对象会被GC回收?

  • 在垃圾收集器进行回收前,第一件事就是确定这些对象哪些还存活,哪些已经死去。

点击 查看 我的另一篇文章 《深入理解Java虚拟机》(三)垃圾收集器与内存分配策略

测试环境

  • 系统

    Microsoft Windows [版本 10.0.14393]
  • JDK
    java version "1.8.0_112"
    Java(TM) SE Runtime Environment (build 1.8.0_112-b15)
    Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)
  • 测试工具
    IntelliJ IDEA 2017.2

示例代码

这里我们来通过一个小程序进行一下堆内存分析,代码如下:

package net.penglei.test;

public class HeapTest {
private static final int _1M = 1024 * 1024; public static void main(String[] args) throws InterruptedException {
byte[] byte1 = new byte[2 * _1M];
byte[] byte2 = new byte[2 * _1M];
byte[] byte3 = new byte[2 * _1M];
byte[] byte4 = new byte[2 * _1M];
byte[] byte5 = new byte[2 * _1M]; byte[] byte6 = new byte[5 * _1M]; byte[] byte7 = new byte[2 * _1M]; }
}

设置JVM 参数配置

-Xms20m
-Xmx20m
-Xmn10m
-verbose:gc
-XX:+PrintGCDetails #输出详细GC日志模式
-XX:+PrintTenuringDistribution #输出每次minor GC后新的存活周期的阈值
-XX:+PrintGCTimeStamps #输出gc的触发时间

我的 IntelliJ IDEA 配置

查看程序进程,堆详情

  • 查看 jps -l 看进程,通过 jmap -heap pid  查看堆的概要信息
$ jps -l
5636 net.penglei.test.HeapTest

堆配置

$ jmap -heap 5636

Attaching to process ID 5636, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.112-b15 using thread-local object allocation.
Parallel GC with 8 thread(s) Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100 #GC后如果发现空闲堆内存占到整个预估堆内存的N%(百分比)
MaxHeapSize = 20971520 (20.0MB) # 堆最大空闲 jvm参数 -Xms20m
NewSize = 10485760 (10.0MB) # 年轻代空间 jvm参数 -Xmn10m
MaxNewSize = 10485760 (10.0MB) # 年轻代最大空间
OldSize = 10485760 (10.0MB) # 老年代空间 =(等于)堆内存大小 -(减去)年轻代大小
NewRatio = 2
SurvivorRatio = 8 # 年轻代内存又被分成三部分 Eden 空间 80% 而From Survivor 空间 和 To Survivor空间 分别占用10%
MetaspaceSize = 21807104 (20.796875MB) # 设置元空间的最大值 jvm参数 -XX:MaxMetaspaceSize
CompressedClassSpaceSize = 1073741824 (1024.0MB) # 类指针压缩空间大小, 默认为1G
MaxMetaspaceSize = 17592186044415 MB # 是分配给类元数据空间的最大值
G1HeapRegionSize = 0 (0.0MB) # G1区块的大小, 取值为1M至32M. 其取值是要根据最小Heap大小划分出2048个区块 ...

执行完 byte3

byte[] byte3 = new byte[2 * _1M];
$ jmap -heap 5636
...
Heap Usage:
PS Young Generation
Eden Space:
capacity = 8388608 (8.0MB)
used = 7635080 (7.281379699707031MB)
free = 753528 (0.7186203002929688MB)
91.01724624633789% used
From Space:
capacity = 1048576 (1.0MB)
used = 0 (0.0MB)
free = 1048576 (1.0MB)
0.0% used
To Space:
capacity = 1048576 (1.0MB)
used = 0 (0.0MB)
free = 1048576 (1.0MB)
0.0% used
PS Old Generation
capacity = 10485760 (10.0MB)
used = 0 (0.0MB)
free = 10485760 (10.0MB)
0.0% used 1628 interned Strings occupying 148560 bytes.
数据区块 堆总容量 使用容量 剩余容量 使用占比
年轻代 8.0MB 7.28MB 0.71MB 91.0%
幸存者0 1.0MB 0.00MB 1.0MB 0.0%
幸存者1 1.0MB 0.00MB 1.0MB 0.0%
老年代 10.0MB 0.00MB 10.MB 0.0%

简单总结

  • PS Young Generation 年轻代空间,使用量达到 91.0%,内存剩余0.71MB,当下次执行byte4(占用年轻代2M内存),会触发Eden Space 空间(年轻代) Minor GC (年轻代垃圾收集)。

  • PS Old Generation 老年代空间,使用量达到 0.00%,内存剩余10.MB,当下次执行 byte4(占用年轻代2M内存),上面 Eden Space 空间(年轻代) Minor GC (年轻代垃圾收集),会老年代占用一部分内存。

执行完 byte4

byte[] byte4 = new byte[2 * _1M]

控制台打印的GC日志

641.638: [GC (Allocation Failure)
Desired survivor size 1048576 bytes, new threshold 7 (max 15)
[PSYoungGen: 7456K->728K(9216K)] 7456K->6880K(19456K), 0.0036244 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs] 641.642: [Full GC (Ergonomics)
[PSYoungGen: 728K->0K(9216K)] [ParOldGen: 6152K->6700K(10240K)] 6880K->6700K(19456K),
[Metaspace: 2848K->2848K(1056768K)], 0.0068164 secs]
[Times: user=0.00 sys=0.00, real=0.01 secs]

GC日志分块图解 ps(画的不好)

$ jmap -heap 5636
...
Heap Usage:
PS Young Generation
Eden Space:
capacity = 8388608 (8.0MB)
used = 2097168 (2.0000152587890625MB)
free = 6291440 (5.9999847412109375MB)
25.00019073486328% used
From Space:
capacity = 1048576 (1.0MB)
used = 0 (0.0MB)
free = 1048576 (1.0MB)
0.0% used
To Space:
capacity = 1048576 (1.0MB)
used = 0 (0.0MB)
free = 1048576 (1.0MB)
0.0% used
PS Old Generation
capacity = 10485760 (10.0MB)
used = 6861768 (6.543891906738281MB)
free = 3623992 (3.4561080932617188MB)
65.43891906738281% used 1556 interned Strings occupying 143760 bytes.

GC日志详细分析

641.638: [GC (Allocation Failure)
Desired survivor size 1048576 bytes, new threshold 7 (max 15)
[PSYoungGen: 7456K->728K(9216K)] 7456K->6880K(19456K), 0.0036244 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]

Parallel Scavenge 是年轻代 GC 收集器

641.638: [GC (Allocation Failure)
  • 1641.638:是本次GC发生的时间,从jvm启动起开始计时,单位为秒。这是一次Minor GC(年轻代垃圾收集),Minor GC 非常频繁,回收速度快。
Desired survivor size 1048576 bytes, new threshold 7 (max 15)
  • 期望的幸存者大小1048576字节,新的存活周期的阈值为7(max 15)。
[PSYoungGen: 7456K->728K(9216K)]

格式为:[PSYoungGen: a->b(c)]

年轻代使用的是多线程垃圾收集器 Parallel Scavenge(新生代收集器,一般采用复制算法,并行的多线程收集器)

  • PSYoungGen,表示 GC发生在年轻代。
  • a 为GC前年轻代已占用空间,年轻代又细分为一个Eden 空间和From Survivor 空间 和 To Survivor空间。
  • b 为 Minor GC之后Eden空间GC后年轻代已占用空间 或者Survivor中已被占用的空间。
  • c 括号里的c表示整个年轻代的大小。
7456K->6880K(19456K)

格式为:x->y(z)

  • x 表示GC前堆的已占用空间,
  • y 表示GC后堆已占用空间,
  • z 表示堆的总大小。
, 0.0036244 secs]
  • 表示本次GC所消耗的时间。
[Times: user=0.00 sys=0.00, real=0.00 secs]
  • 提供cpu使用及时间消耗,user是用户态消耗的cpu时间,sys是系统态消耗的cpu时间,real是实际的消耗时间。

老年代占用内存空间 计算方式

  • 老年代的内存大小 = (等于) 堆内存总大小 - (减去)年轻代内存大小。
  • 此例中就是19456K - 9216K = 10240K

Parallel Old 是Parallel Scavenge 收集器的老年代版本

641.642: [Full GC (Ergonomics)
[PSYoungGen: 728K->0K(9216K)] [ParOldGen: 6152K->6700K(10240K)] 6880K->6700K(19456K),
[Metaspace: 2848K->2848K(1056768K)], 0.0068164 secs]
[Times: user=0.00 sys=0.00, real=0.01 secs]
641.642: [Full GC (Ergonomics)

老年代GC 又称为Major GC,经常会伴随一次Minor GC(年轻代垃圾回收)速度比较慢

  • 641.642:是本次GC发生的时间,从jvm启动起开始计时,单位为秒。[Full GC (Ergonomics) ,表示执行全局垃圾回收
[PSYoungGen: 728K->0K(9216K)]

格式为:[PSYoungGen: a->b(c)]

年轻代使用的是多线程垃圾收集器 Parallel Scavenge(新生代收集器,一般采用复制算法,并行的多线程收集器)

  • PSYoungGen,表示 GC发生在年轻代。
  • a 为GC前年轻代已占用空间,年轻代又细分为一个Eden 空间和From Survivor 空间 和 To Survivor空间。
  • b 为 Minor GC之后Eden空间GC后年轻代已占用空间 或者Survivor中已被占用的空间。
  • c 括号里的c表示整个年轻代的大小。
[ParOldGen: 6152K->6700K(10240K)]

格式为:[ParOldGen: x->y(z)]

老年代GC,使用 Parallel Old收集器,是Parallel Scavenge收集器的老年代版本,一搬采用多线程和“标记-整理”算法

  • ParOldGen 表示 GC 发生在老年代。
  • x 为GC前老年代已占用空间
  • y 为GC后老年代已占用空间
  • 括号里的 z 为整个老年代的大小
6880K->6700K(19456K)

格式为:e->f(g)]

  • e 为GC前堆堆内存占用,
  • f 为GC后堆堆内存占用,
  • 括号里的 g 为JVM整个堆的总大小。
[Metaspace: 2848K->2848K(1056768K)]

java8 特性是 把永久代 (Permanent Generation (PermGen)) 移植到元空间(Metaspace)

格式为:t->y(u)]

JDK8 HotSpot JVM 使用本地内存来存储类元数据信息并称之为:元空间(Metaspace);这与Oracle JRockit 和IBM JVM’很相似。这将是一个好消息:意味着不会再有java.lang.OutOfMemoryError: PermGen问题

默认情况下,类元数据只受可用的本地内存限制(容量取决于是32位或是64位操作系统的可用虚拟内存大小)

  • t 为元空间的垃圾回收前内存占用
  • y 为元空间的垃圾回收后内存占用
  • 括号里的 u 为JVM元空间内存总大小
, 0.0068164 secs]
  • 表示本次GC所消耗的时间。
[Times: user=0.00 sys=0.00, real=0.01 secs]

提供cpu使用及时间消耗

  • user :用是用户态消耗的cpu时间
  • sys :是系统态消耗的cpu时间
  • real :本次GC是实际的消耗时间
数据区块 堆总容量 使用容量 剩余容量 使用占比
年轻代 8.0MB 2.00MB 5.99MB 25.0%
幸存者0 1.0MB 0.00MB 1.00MB 0.0%
幸存者1 1.0MB 0.00MB 1.00MB 0.0%
老年代 10.0MB 6.54MB 3.45MB 65.4%

简单总结

  • 年轻代 Eden Space 空间,使用量达到 25.0%,内存剩余5.99MB,当下次执行byte5(占用年轻代2M内存) 不会触发年轻代 Eden Space 空间 Minor GC(年轻代垃圾收集)。

  • 老年代空间,使用量达到 6.54%,内存剩余3.45MB,当下次执行byte5(占用年轻代2M内存),不会触发老年代空间 Major GC(老年代垃圾收集),因为年轻代空间还够用。

执行完 byte5

byte[] byte5 = new byte[2 * _1M];
$ jmap -heap 5636
...
Heap Usage:
PS Young Generation
Eden Space:
capacity = 8388608 (8.0MB)
used = 4356568 (4.154747009277344MB)
free = 4032040 (3.8452529907226562MB)
51.9343376159668% used
From Space:
capacity = 1048576 (1.0MB)
used = 0 (0.0MB)
free = 1048576 (1.0MB)
0.0% used
To Space:
capacity = 1048576 (1.0MB)
used = 0 (0.0MB)
free = 1048576 (1.0MB)
0.0% used
PS Old Generation
capacity = 10485760 (10.0MB)
used = 6861768 (6.543891906738281MB)
free = 3623992 (3.4561080932617188MB)
65.43891906738281% used 1556 interned Strings occupying 143760 bytes.
数据区块 堆总容量 使用容量 剩余容量 使用占比
年轻代 8.0MB 4.15MB 3.84MB 51.9%
幸存者0 1.0MB 0.00MB 1.00MB 0.0%
幸存者1 1.0MB 0.00MB 1.00MB 0.0%
老年代 10.0MB 6.54MB 3.45MB 65.4%

简单总结

  • 年轻代 Eden Space 空间,使用量达到 51.9%,内存剩余3.84MB,当下次执行byte6(占用年轻代5M内存),导致年轻代空间不够用了, 会触发年轻代 Eden Space 空间 Minor GC(年轻代垃圾收集),把一部分内存转移到 PS Old Generation 老年代。

  • 老年代 PS Old Generation 空间,使用量达到 6.54%,内存剩余3.45MB,当下次执行byte6(占用年轻代5M内存),由于年轻代的一部分内存,转移到了老年代,导致老年代空间不够用了,会触发老年代 PS Old Generation 空间 Major GC(老年代垃圾收集)。

执行完 byte6

byte[] byte6 = new byte[5 * _1M];

控制台打印的GC日志

10342.704: [

Full GC (Ergonomics) 

		 [PSYoungGen: 4254K->2048K(9216K)]
[ParOldGen: 6700K->8745K(10240K)]
10955K->10793K(19456K),
[Metaspace: 2848K->2848K(1056768K)], 0.0154383 secs
] [Times: user=0.00 sys=0.03, real=0.02 secs]

这个GC 日志详细解读请参考,上面解读,执行完 byte4 的日志 ps(那个解读更详细)

  • 这个是日志其实说的就是 :年轻代G回收前后,老年代GC回收前后,整个堆的GC回收前后,原数据空间回收前后,的内存使用情况。三个内存区块GC回收所消耗的时间,提供cpu使用及时间消耗时间

简单解读GC日志

  • PS Young Generation 年轻代 Eden Space 空间,使用量达到 4254K,当执行byte6(占用年轻代5M内存),导致年轻代空间不够用了,会先触发年轻代 Eden Space 空间 Minor GC(年轻代垃圾收集),把一部分内存转移到 PS Old Generation 老年代,GC回收后 Eden Space 空间 剩余 2048K。

  • PS Old Generation 老年代空间,使用量达到 6700K,当执行byte6(占用年轻代5M内存),由于年轻代的一部分内存,转移到了老年代,导致老年代空间不够用了,会先触发老年代 PS Old Generation 空间 Major GC(老年代垃圾收集)。GC回收后 Eden Space 空间 剩余 8745K。

$ jmap -heap 5636
...
Heap Usage:
PS Young Generation
Eden Space:
capacity = 8388608 (8.0MB)
used = 7507856 (7.1600494384765625MB)
free = 880752 (0.8399505615234375MB)
89.50061798095703% used
From Space:
capacity = 1048576 (1.0MB)
used = 0 (0.0MB)
free = 1048576 (1.0MB)
0.0% used
To Space:
capacity = 1048576 (1.0MB)
used = 0 (0.0MB)
free = 1048576 (1.0MB)
0.0% used
PS Old Generation
capacity = 10485760 (10.0MB)
used = 8955872 (8.540985107421875MB)
free = 1529888 (1.459014892578125MB)
85.40985107421875% used 1556 interned Strings occupying 143760 bytes.
数据区块 堆总容量 使用容量 剩余容量 使用占比
年轻代 8.0MB 7.16MB 0.83MB 89.5%
幸存者0 1.0MB 0.00MB 1.00MB 0.0%
幸存者1 1.0MB 0.00MB 1.00MB 0.0%
老年代 10.0MB 8.54MB 1.45MB 85.4%

执行完 byte7

byte[] byte7 = new byte[2 * _1M];

简单总结

  • 参考 byte6 执行后,PS Young Generation 年轻代 Eden Space 空间,使用量达到 89.5%,内存剩余0.83MB,执行byte7(占用年轻代2M内存),导致年轻代空间不够用了,会触发Eden Space 空间(年轻代) Minor GC (年轻代垃圾收集)
  • 参考 byte6 执行后,PS Old Generation 老年代空间,使用量达到 85.4%,内存剩余1.45MB,执行byte7(占用年轻代2M内存),会导致年轻代的GC回收放到老年代,而老年代也承担不了,会 OutOfMemoryError

控制台打印的GC日志

10427.298: [Full GC (Ergonomics) [PSYoungGen: 7331K->7168K(9216K)] [ParOldGen: 8745K->8745K(10240K)] 16077K->15913K(19456K), [Metaspace: 2849K->2849K(1056768K)], 0.0065366 secs] [Times: user=0.09 sys=0.02, real=0.01 secs] 

10427.305: [Full GC (Allocation Failure) [PSYoungGen: 7168K->7168K(9216K)] [ParOldGen: 8745K->8745K(10240K)] 15913K->15913K(19456K), [Metaspace: 2849K->2849K(1056768K)], 0.0027873 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Heap
at net.penglei.test.HeapTest.main(HeapTest.java:16)
PSYoungGen total 9216K, used 7462K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
eden space 8192K, 91% used [0x00000000ff600000,0x00000000ffd49b60,0x00000000ffe00000)
from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
to space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
ParOldGen total 10240K, used 8745K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
object space 10240K, 85% used [0x00000000fec00000,0x00000000ff48a708,0x00000000ff600000)
Metaspace used 2880K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 309K, capacity 386K, committed 512K, reserved 1048576K
Disconnected from the target VM, address: '127.0.0.1:59679', transport: 'socket' Process finished with exit code 1 。
[Full GC (Ergonomics) [PSYoungGen: 7331K->7168K(9216K)]
  • 本次 Minor GC 发生在PS Young Generation 年轻代 Eden Space 空间,由于老年代已经占用85.4%,老年代空间不够用,本次年轻代垃圾回收没什么太大作用,只回收了一丢丢。
[ParOldGen: 8745K->8745K(10240K)]
  • 本次 Major GC 发生在 PS Old Generation 老年代 ,由于老年代已经占用85.4% , 空间不够回收用,导致老年代回收没有效果**
16077K->15913K(19456K)

这些是告诉你,Exception 前 内存溢出前的堆占用情况

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Heap
at net.penglei.test.HeapTest.main(HeapTest.java:16)
PSYoungGen total 9216K, used 7462K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
eden space 8192K, 91% used [0x00000000ff600000,0x00000000ffd49b60,0x00000000ffe00000)
from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
to space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
ParOldGen total 10240K, used 8745K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
object space 10240K, 85% used [0x00000000fec00000,0x00000000ff48a708,0x00000000ff600000)
Metaspace used 2880K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 309K, capacity 386K, committed 512K, reserved 1048576K
  • 此刻的 PS Young Generation 年轻代JVM 堆回收前占用16077K,年轻代JVM 堆回收后占用16077K ,JVM 堆总大小 19456K
[Full GC (Allocation Failure)
[PSYoungGen: 7168K->7168K(9216K)] [ParOldGen: 8745K->8745K(10240K)] 15913K->15913K(19456K)
  • PSYoungGen 年轻代 Minor GC , ParOldGen 老年代 Major GC 老年代承担不了 15913K 内存,然后就 OutOfMemoryError 堆内存溢出了

  • 为什了 老年代这次要 承担15913K 内存呢?因为前两次 Full GC 都没有成功,导致内存积压了一些在堆空间,堆空间自然放不下,然后要放到老年代,老年代放不下就堆内存溢出了

总结 内存分配与回收策略

  • 对象优先在新生代分配

  • 大对象直接进入老年代

  • 长期存活的对象将进入老年代

  • 动态对象年龄判断:如果在Survivor空间中相同年龄所有对象大小总和大于Survivor空间的一半,大于或等于该年龄的对象直接进入老年代。

  • 空间分配担保:发生Minor GC前,虚拟机会先检查老年代最大可用连续空间是否大于新生代所有对象总空间,如果不成立,虚拟机会查看HandlePromotionFailure设置值是否允许担保失败,如果允许继续检查老年代最大可用的连续空间是否大于历次晋升到老年代的平均大小,如果大于会尝试进行一次Minor GC;如果小于或者不允许冒险,会进行一次Full GC。

1 对象优先在eden分配

大多数情况下,对象优先在新生代的Eden区分配。 当Eden区没有足够的空间时,虚拟机将发起一次Minor GC。 Minor GC与Full GC。

  • Minor GC:新生代GC,非常频繁,回收速度快。
  • Fulll GC:老年代GC,又称为Major GC,经常会伴随一次Minor GC,速度比较慢。

2 大对象直接进入老年代

  • 大对象是指需要大量连续的内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组。

  • 虚拟机提供了一个参数:PretenureSizeThreshold,大于这个参数的对象将直接在老年代分配。

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

  • 虚拟机给每个对象定义了一个对象年龄计数器(Age),对象每经过一次Minor GC后仍然存活,且能被Survivor容纳的话,年龄就 +1 ,当年龄增加到一定程度(默认为15),就会被晋升到老年代中,这个阈值可以通过参数 MaxTenuringThreshold 来设置。

4.动态对象年龄的判定

4 动态对象年龄判定

  • 如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。

5 空间分配担保

  • 为了更好的适应不同程序的内存状况,对象年龄不是必须到达阈值才会进入老年代。
  • 只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将进行Full GC。

转至:http://www.ymq.io/2017/08/10/jvm-6-gc-log/

《深入理解Java虚拟机》(六)堆内存使用分析,垃圾收集器 GC 日志解读的更多相关文章

  1. 读书笔记,《深入理解java虚拟机》,第三章 垃圾收集器与内存分配策略

    要实现虚拟机,其实人们主要考虑完成三件事情: 第一,哪些内存需要回收: 第二,什么时候回收: 第三,如何回收. 第二节,对象已死吗    垃圾收集其实主要是针对java堆里面的数据来说的,传统的垃圾收 ...

  2. 《深入理解Java虚拟机》之(二、垃圾收集器与内存分配策略)

    程序计数器.虚拟机栈.本地方法栈3个区域随线程而生,随线程而灭,这几个区域的内存分配和回收都具备确定性,不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟着回收了,而java堆和方法区 ...

  3. 深入理解Java虚拟机学习笔记(二)-----垃圾收集器与内存分配策略

    写在前面 本节常见面试题: 如何判断对象是否死亡(两种方法). 简单的介绍一下强引用.软引用.弱引用.虚引用(虚引用与软引用和弱引用的区别.使用软引用能带来的好处). 如何判断一个常量是废弃常量 如何 ...

  4. 深入理解Java虚拟机(六)——JVM调优分析与实战

    大内存硬件上的程序部署策略 单个虚拟机管理大内存 出现问题 如果JVM中的堆内存太小,就会频繁地出发GC,而每次GC会将用户线程暂停,所以,频繁地GC会导致长时间的停顿.如果扩大计算的内存的大小,就能 ...

  5. 《深入理解 java 虚拟机》学习 -- 内存分配

    <深入理解 java 虚拟机>学习 -- 内存分配 1. Minor GC 和 Full GC 区别 概念: 新生代 GC(Minor GC):指发生在新生代的垃圾收集动作,因为 Java ...

  6. Java虚拟机垃圾回收(三) 7种垃圾收集器

    Java虚拟机垃圾回收(三) 7种垃圾收集器 主要特点 应用场景 设置参数 基本运行原理 在<Java虚拟机垃圾回收(一) 基础>中了解到如何判断对象是存活还是已经死亡?在<Java ...

  7. Java虚拟机笔记(四):垃圾收集器

    前言 前一篇文章介绍了内存的垃圾收集算法,现在介绍下内存回收的具体实现--垃圾收集器. 由于Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商,不同版本的虚拟机所提供的垃圾收集 ...

  8. 深入理解Java虚拟机(自动内存管理机制)

    文章首发于公众号:BaronTalk 书籍真的是常读常新,古人说「书读百遍其义自见」还是很有道理的.周志明老师的这本<深入理解 Java 虚拟机>我细读了不下三遍,每一次阅读都有新的收获, ...

  9. 【深入理解Java虚拟机】自动内存管理机制——内存区域划分

      Java与C++之间有一堵有内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来.C/C++程序员既拥有每一个对象的所有权,同时也担负着每一个对象生 ...

随机推荐

  1. 根据word模板dotx文件创建word

    doc = this._wordApplication.Documents.Add(@"D:\Fdsfsdsfsdfds.dotx"); 用这个会把模板的样式,文字内容都创建到新w ...

  2. hdu 1069 Monkey and Banana 【动态规划】

    题目 题意:研究人员要测试猴子的IQ,将香蕉挂到一定高度,给猴子一些不同大小的箱子,箱子数量不限,让猩猩通过叠长方体来够到香蕉. 现在给你N种长方体, 要求:位于上面的长方体的长和宽  要小于  下面 ...

  3. visual studio单项目一次生成多框架类库、多框架项目合并

    目录 不同平台框架项目使用同一套代码,一次编译生成多个框架类库 需要先了解的东西 分析 添加PropertyGroup 多目标平台 编译符号和输出目录设置 添加依赖 代码文件处理 主副平台项目文件处理 ...

  4. KMP string pattern matching

    The function used here is from the leetcode. Details can be found in leetcode problem: Implement str ...

  5. 前端学习之路-CSS介绍,Html介绍,JavaScript介绍

    CSS介绍 学前端必备掌握CSS样式,css为层叠样式表,用来定义页面的显示效果,加强用户的体验乐趣,那么如何用css到html中呢? style属性方式 利用标签中的style属性来改变显示样式 & ...

  6. LabVIEW(十五):右键菜单添加创建VI模版

    如果在项目研究中使用到的某一个模版文件次数较多,可以单独为某一个模版文件新建右键选项.以文本格式打开注册表,添加的右键内容即为Data后面的内容.Reg内容不可手动修改,可以通过LabVIEW的编程实 ...

  7. webpack通过postcss-loader添加浏览器前缀

    在webpack中,我们可以很方便的使用autoprefixer来为css3属性添加不同的浏览器前缀. 首先,需要安装autoprefixer不用多说了,其次是安装postcss-loader(npm ...

  8. 使用pyenv来管理python版本

    使用pyenv可以很方便的切换python版本,而不会影响系统的python版本,对需要使用supervisor(仅支持python2)托管程序,项目使用python3开发的情况十分有用 pyenv的 ...

  9. Java language

    1.Java开发环境: java编译运行过程: 1. 编译期:.java源文件,经过编译,生成.class字节码文件 2. 运行期:JVM加载.class并运行.class - 特点:跨平台.一次编程 ...

  10. [git与github]__git与github简单了解

    前言 关于版本控制,版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统. 我们通过版本控制系统可以解决的问题:可以非常方便的查看我们的源码文件的历代更新版本.或将我们的项目源 ...