应用JConsole学习Java GC

关于Java GC的知识,好多地方都讲了很多,今天我用JConsole来学习一下Java GC的原理。

GC原理

在我的上一篇中介绍了Java运行时数据区,在了解这些的基础上,对Java GC的理解能更清晰一些。

简单来讲,Java的内存分为堆和栈,其中堆是程序员用的内存,栈是系统用的内存。(这句话不一定正确,但可以这么理解)Java的内存管理主要是管理对象的分配和释放,或者说内存的分配和回收。在C或C++语言里面,内存是要自己控制的,new之后要delete掉,否则很容易出现内存泄漏。(还记得当时写C的痛苦,不过通过写C代码,很好的了解了内存的分配机制)在Java里面,分配内存和回收内存的事情是Jvm来管的。

Jvm有自己的机制来管理内存,具体的细节算法这里不讲,主要讲大概的处理方式。Jvm的GC主要处理堆内存,JVM内存模型中的堆可以细分为Young Generation和Old Generation(又称为Tenure Space),其中Young Generation又分为Eden Space(Eden是伊甸园的意思,老鹰乐队有首歌叫Long Road out of Eden)和Survivor spaces。如下图所示:

具体GC的过程如下:

  1. 在Young Generation中,有一个叫Eden Space的空间,主要是用来存放新生的对象,还有两个Survivor Spaces(from、to),它们的大小总是一样,它们用来存放每次垃圾回收后存活下来的对象。
  2. 在Old Generation中,主要存放应用程序中生命周期长的内存对象。
  3. 在Young Generation块中,垃圾回收一般用Copying的算法,速度快。每次GC的时候,存活下来的对象首先由Eden拷贝到某个SurvivorSpace,当Survivor Space空间满了后,剩下的live对象就被直接拷贝到OldGeneration中去。因此,每次GC后,Eden内存块会被清空。
  4. 在Old Generation块中,垃圾回收一般用mark-compact的算法,速度慢些,但减少内存要求。
  5. 垃圾回收分多级,0级为全部(Full)的垃圾回收,会回收OLD段中的垃圾;1级或以上为部分垃圾回收,只会回收Young中的垃圾,内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况。

翻译成为更简单的语言:

  1. 内存首先在Eden中分配;
  2. Eden中满了之后,挪到Survivor Space,清空Eden;
  3. Survivor Space满了之后,挪到Old Generation;
  1. 如果这三个区域都满了,内存溢出OutOfMemory。

那上面这个过程如何得知呢?今天我就用JConsole给大家演示一下如何看GC的过程。

JConsole介绍

先介绍一下JConsole。

JConsole是什么

JConsole 是一个内置 Java 性能分析器,可以从命令行或在 GUI shell 中运行。您可以轻松地使用 JConsole(或者,它更高端的 “近亲” VisualVM )来监控 Java 应用程序性能和跟踪 Java 中的代码。

如何启动JConsole

JConsole是一个程序,在windows里面找到JConsole.exe,双击启动即可。启动之后的界面如下图所示:

可以看到,JConsole即可以连接本地进程,也可以连接远程进程。

应用JConsole学习GC

那么,如何用JConsole学习GC的过程呢?我们首先要设计一个程序,这个程序一直保持内存增长,直到发生内存泄漏。在这个过程中,我们应该JConsole观察GC的过程。

写一个内存泄漏的程序

写一个内存泄漏的程序比较简单,读一个很大的文件到内存中,直至内存溢出,代码如下:

package com.chzhao.test;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List; public class StringTest {
public static void main(String[] args) throws InterruptedException,
IOException {
List<String> list = new ArrayList<String>();
String file = "d:/wisdombud-unicom.log.2014-12-05";
BufferedReader in = null;
in = new BufferedReader(new FileReader(file));
while (true) {
String lineMsg = in.readLine();
if (lineMsg == null || lineMsg.equals("")) {
break;
}
list.add(lineMsg);
Thread.sleep(10);
System.out.println(list.size());
}
in.close();
}
}

这个文件是我程序的一个日志文件,足够大,300M+

设置启动参数

除了写程序之外,为了快点出现内存泄漏,我们把启动内存调小。在Eclispse里面调VM arguments就可以,内容为:

-Xms4M -Xmx4M

我设置了4M。

通过JConsole观察

首先把程序运行起来,在通过JConsole连接到程序上。

因为我们只关心内存,切换到内存标签页。有一个下拉图表,可以观察不同的内存情况。右下角有个柱状图,显示的是堆内存和栈内存的占用情况。其中堆内存包括Eden Space、Survivor Space和Tenured Gen。如下图所示:

可以看到,随着程序的运行,Eden Space会逐渐变满,到100%之后,Eden Space会变成0%,Survivor Space会变大;Survivor Space变100%之后,会挪到Tenured Gen中,Survivor Space变0%。这个过程和上面讲到的GC过程是一样的,很直观。

也可以观察上面的曲线图,Eden Space的图是类似波形图,每次到波谷都是进行了一次GC。Tenured Gen则是类似梯田,一直向上涨,直到内存溢出。如下两张图所示。

Eden Space的波形图

Tenured Gen的波形图

在VM摘要标签页,能看到更多JVM的信息,可以看到分配的内存已经等于堆的最大值了,所以内存溢出。(为什么堆的最大值是5942Kb我没搞明白,不应该小于4M吗?如果哪位懂请指点一下。

结论

通过JConsole工具学习GC的过程,生动形象,很容易明白GC是如何进行的。然而这些知识都属于GC的基础知识,如果要了解更多GC的知识,还要多学习。

参考:

应用JConsole学习Java GC的更多相关文章

  1. Java GC回收机制

    优秀Java程序员必须了解的GC工作原理 一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,因为有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只 ...

  2. Java GC(垃圾回收)机制知识总结

    目录 Java GC系列 Java关键术语 Java HotSpot 虚拟机 JVM体系结构 Java堆内存 启动Java垃圾回收 Java垃圾回收过程 垃圾回收中实例的终结 对象什么时候符合垃圾回收 ...

  3. java gc的工作原理、如何优化GC的性能、如何和GC进行有效的交互

    java gc的工作原理.如何优化GC的性能.如何和GC进行有效的交互 一个优秀的Java 程序员必须了解GC 的工作原理.如何优化GC的性能.如何和GC进行有效的交互,因为有一些应用程序对性能要求较 ...

  4. Java GC系列(4):垃圾回收监视和分析

    本文由 ImportNew - lomoxy 翻译自 javapapers. 目录 垃圾回收介绍 垃圾回收是如何工作的? 垃圾回收的类别 垃圾回收监视和分析 在这个Java GC系列教程中,让我们学习 ...

  5. Java GC 概念摘要

    很长时间,我想Java的GC做一个小小的总结,他有没有时间.根据最近看了java paper向上java gc文章,我觉得好,读读.顺便说一下,总结下. java paper的GC文章地址,里面有非常 ...

  6. Java GC 专家系列3:GC调优实践

    本篇是”GC专家系列“的第三篇.在第一篇理解Java垃圾回收中我们学习了几种不同的GC算法的处理过程,GC的工作方式,新生代与老年代的区别.所以,你应该已经了解了JDK 7中的5种GC类型,以及每种G ...

  7. Java GC专家系列1:理解Java垃圾回收

    了解Java的垃圾回收(GC)原理能给我们带来什么好处?对于软件工程师来说,满足技术好奇心可算是一个,但重要的是理解GC能帮忙我们更好的编写Java应用程序. 上面是我个人的主观的看法,但我相信熟练掌 ...

  8. JAVA GC之标记 第五节

    JAVA GC之标记  第五节 OK,我们继续昨天最后留下的问题,什么是标记?怎么标记? 第一个问题相信大家都知道,标记就是对一些已死的对象打上记号,方便垃圾收集器的清理. 至于怎么标记,一般有两种方 ...

  9. Java GC - 监控回收行为与日志分析

    1. 简介 在上一篇介绍<Java GC - 垃圾回收机制>, 本文将介绍如何监控 Javc GC 行为,同时涉及一些GUI工具的使用(虽然有些已经很老并不再更新),监控GC在于判断JVM ...

随机推荐

  1. MySQL增加列,移动列

    ALTER TABLE test ADD COLUMN id INT UNSIGNED NOT NULL auto_increment PRIMARY KEY FIRST 给表添加列是一个常用的操作, ...

  2. [LeetCode#247] Strobogrammatic Number II

    Problem: A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked a ...

  3. Codeforces Round #254 (Div. 2) B. DZY Loves Chemistry (并查集)

    题目链接 昨天晚上没有做出来,刚看题目的时候还把题意理解错了,当时想着以什么样的顺序倒,想着就饶进去了, 也被题目下面的示例分析给误导了. 题意: 有1-n种化学药剂  总共有m对试剂能反应,按不同的 ...

  4. Lost connection to MySQL server at 'reading initial communication packet' 错误解决

    Lost connection to MySQL server at 'reading initial communication packet' 错误解决 上次解决了这个问题,今天又碰到,突然失忆, ...

  5. 【Java学习笔记】Hello world

    package aaa; public class aaa { public static void main(String args[]){ System.out.println("hel ...

  6. PS流格式

    概念: 将具有共同时间基准的一个或多个PES组合(复合)而成的单一的数据流称为节目流(Program Stream). ES是直接从编码器出来的数据流,可以是编码过的视频数据流,音频数据流,或其他编码 ...

  7. 载入在线jQuery库

    以百度库为例 <script src="http://libs.baidu.com/jquery/1.11.1/jquery.min.js"></script&g ...

  8. liunx下mysql数据库使用之三范式,关系模型设计注意项,安装目录结构

    数据库的三范式第一范式===>每行记录的属性,是原子的,拆到不可拆为止.===>例如:一个人的籍贯,可以拆分为,省,市,县,乡,村 第二范式===>每行记录的非主属性(非主键属性), ...

  9. 安卓dalvik和art区别

    Dalvik模式像是一台折叠自行车,每次骑之前都要组装后才能上路.而ART模式就是一个已经装好的自行车,直接就能上车走人.所以ART模式在效率上肯定是要好于Dalvik. 通过以上这种表格,我们可以直 ...

  10. C/C++面试小知识点

    1.static有什么用途. 解答: 在函数体中,一个被声明为静态的变量在这一函数被调用过程中维持其值不变. 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所有函数访问,但不能被模块外其 ...