QCon 演讲火热征集中,快来分享你的技术实践与洞见! 了解详情
写点什么

可视化 Java 垃圾回收

  • 2014-02-26
  • 本文字数:2601 字

    阅读完需:约 9 分钟

垃圾回收,就像双陆棋一样,只需几分钟来学习,但要用一生来精通。

Ben Evans 是一名资深培训师兼顾问,他在演讲可视化垃圾回收中从基础谈起讨论了垃圾回收。

以下是对其演讲的简短总结。

基础

当谈到释放不再使用的内存,垃圾回收已经在很大程度上取代了早期技术,比如手动内存管理和引用计数。

这是件好事,因为内存管理令人厌烦,学究式地簿记是计算机擅长的,而不是人擅长的。在这方面,语言的运行时环境比人强。

现代的垃圾回收非常高效,远远超过早期语言中典型的手工分配。通常,具有其它语言背景的人只盯着垃圾回收造成的中断,却没有完全理解自动内存管理发生作用的上下文环境。

标记 & 清除是 Java(及其它运行时环境)用于垃圾回收的基本算法。

在标记 & 清除算法中,引用会从每个线程栈的桢指向程序的堆。所以,从栈开始,循着指针找到所有可能的引用,然后再循着这些引用递归下去。

当递归完成,就找到了所有的活对象,其它的都是垃圾。

请注意,人们经常漏掉的一点是,运行时环境本身也有一个“分配清单(allocation list)”,上面列出了指向每个对象的指针,该列表由垃圾回收器负责维护,并帮助垃圾回收器进行垃圾清理。因此,运行时环境总是可以找出由它创建但尚未回收的对象。

图一

上面插图中所示的栈只是一个与单个应用程序线程相关的栈;每个应用程序线程都有一个类似的栈,每个栈本身都有一组指向堆的指针。

如果垃圾回收器试图在应用程序运行过程中获取活对象的快照,那么它就要追踪运动着的目标,那样很容易漏掉一些严重超时的对象分配,因而无法获得一个准确的快照。因此,“Stop the World”是有必要的;也就是,停止应用程序线程足够长的时间,以便捕获活对象的快照。

下面是垃圾回收器必须遵循的两条黄金法则:

  1. 垃圾回收器必须回收所有的垃圾。
  2. 垃圾回收器必须从不回收任何活对象。

但这两条规则并不是对等的;如果违反了第二条规则,结果会使数据遭到破坏。

另一方面,如果违反了第一条规则,则会是另一种情况,系统并不总是能够回收所有的垃圾,但最终会回收所有的垃圾,那么这是可以接受的,而实际上,这是垃圾回收器的基本原理。

HotSpot

现在,我们来说下 HotSpot,它实际上是一个 C、C++ 以及许多特定于平台的汇编程序组成的混合体。

当人们想到解释器,就会想到一个很大的 while 循环,其中包含一个很长的 switch 语句。但 HotSpot 解释器比那个要复杂的多(由于性能原因)。在开始阅读 JDK 源代码的时候,就会发现 HotSpot 中实在是有许多汇编程序代码。

对象创建

Java 会预先分配大量的连续空间,就是我们所说的“堆”。之后,HotSpot 完全在用户空间里管理这块内存。

如果一个 Java 进程占用了大量的系统(或内核)时间,那么毫无疑问,它不是在进行垃圾回收——因为所有的垃圾回收内存“簿记(bookkeeping)”都是在用户空间进行的。

内存池

图二

“永久代(PermGen)”是一个存储区域,用于保存那些需要在程序生存期内一直存活的东西,如类的元数据。不过,随着应用程序服务器的出现,它们有自己的类加载器,并且需要重新加载类的元数据,永久代作为一个优化决策开始显得糟糕,所幸,它在 Java 8 中消失了。

Java 8 将会使用一个名为“元空间(Metaspace)”的新概念。元空间与永久代并不完全相同。它在堆的外面,由操作系统管理。这意味着,它不会在 Java 堆中,而是在本地内存里。目前,这还不是一个非常好的消息,因为没有多少工具能够让用户轻松地查看本地内存。所以,永久代消失是件好事,但工具赶上这个变化还需要一些时间。

Java 堆布局

现在,我们来看下 Java 堆。注意堆空间之间的虚拟空间。它们提供了一点浮动量,以允许对内存池进行一定量的尺寸调整,又不用为任何对象移动付出代价。

图三

“弱代假设(Weak Generational Hypothesis)”

就现状而言,究竟为什么要将堆分成所有这些内存池?

图四

有的运行时事实无法通过静态分析推导出来。上面的插图说明有两组对象:一组存活时间短,一组存活时间长——所以,做额外的簿记以便利用这一事实是有意义的。在 Java 平台中,有许多类似的作为优化写入平台的事实。

演示

Ben Evans 进行了一系列的动画演示。第一个演示是个 Flash,说明了对象在 Eden 区和一个新生代 Survivor 空间之间移动,并最终进入老年代的过程。

图五是用 JavaFX 再现了同样的过程。

图五

运行时开关

‘强制性’参数

  • -verbose:gc——为用户输出一些 GC 信息
  • -Xloggc:< 文件路径 >——指定日志输出路径,要确保磁盘有空间
  • -XX:+PringGCDetails——为辅助工具提供“最低限度信息(Minimum information)” ——用这个参数代替 -verbose:gc
  • –XX:PrintTenuringDistribution——“过早提升(Premature promotion)”信息

基本堆大小参数

  • -Xms —— 设置预留给堆的最小内存值
  • -Xmx —— 设置预留给堆的最大内存值
  • -XX:MaxPermSize=——设置永久代的最大内存值 ——有利于 Spring 应用程序和应用服务器

以前,我们被教导要把 -Xms 和 -Xmx 的值设的一样大。不过这已经变了。因此,现在可以为 -Xms 设置一个合理范围内较小的值,或者根本就不设置,因为堆的适应能力现在已经非常好了。

其它参数

  • -XX:NewRatio=N
  • -XX:NewSize=N
  • -XX:MaxNewSize=N
  • -XX:MaxHeapFreeRatio
  • -XX:MinHeapFreeRatio
  • -XX:SurvivorRatio=N
  • -XX:MaxTenuringThreshold=N

图六

为什么要有日志文件

日志文件的好处是能够用于取证分析,可以使用户免于为了再现问题而不得不再执行一次代码(如果是一个罕见的生产环境错误,那么重现并不容易)。

另外,它们包含的信息比针对内存的 JMX MXBeans 所能提供的信息更多,且不说轮询 JMX 本身会引入一系列 GC 问题。

工具

  • HP JMeter(用 Google 查询一下)——免费,非常可靠,但不再提供支持 / 功能增强
  • GCViewer ——免费,开源,但界面有点丑
  • GarbageCat ——名字最好听
  • IBM GCMV ——支持 J9
  • jClarity Censum ——界面最美观,而且最有用——不过,这是我们的偏见!

小结

  • 需要了解一些 GC 基础理论
  • 要让新生代的大部分对象在年轻时死亡
  • 打开 GC 日志!——原始日志文件难以阅读——使用工具
  • 使用工具来帮助自己调优——测量,而不是猜测

查看完整演讲视频,请点击这里

关于作者

Ben Evans是一家 Java/JVM 性能分析创业公司 jClarity 的 CEO。在业余时间,他是伦敦 Java 社区的一名负责人,也是 Java 社区过程执行委员会成员之一。他先前的项目包括:对 Google IPO、金融交易系统做性能测试,为若干 90 年代最大的电影开发获奖网站等等。

查看英文原文:**** Visualizing Java Garbage Collection

2014-02-26 06:388450
用户头像

发布了 256 篇内容, 共 87.1 次阅读, 收获喜欢 12 次。

关注

评论

发布
暂无评论
发现更多内容

翻译: Effective Go (1)

申屠鹏会

翻译 Go 语言

WebSphere Application Server运维实践 --从入门到监控

rafe

Java WAS perfservlet visualVM JMX

毕竟,一生很短,少有圆满

霍太稳@极客邦科技

创业 身心健康 个人成长

走出舒适区最好办法别走了,扩大它

乐少

对话 CTO〡和 PingCAP CTO 黄东旭聊开源数据库新蓝海

ONES 王颖奇

数据库 分布式 开发者

为什么你的创业公司应该运行在Kubernetes上

云原生

云原生 k8s

业务系统开发程序员常用linux知识

程序员劝退师

Linux

uni-app黑魔法:小程序自定义组件运行到H5平台

崔红保

小程序 uni-app

2020了,各家小程序发展的怎么样?

崔红保

小程序 uni-app

近两年影响我的两个重要原则

Selina

【Vue3.0 Beta】尝鲜

德育处主任

CSS Java html5 Vue 大前端

此为开卷

X.F

从流程、认知上做稳定的系统演进

Skysper

系统设计 质量管理

一文讲清楚 MySQL 事务隔离级别和实现原理,开发人员必备知识点

古时的风筝

MySQL 数据库 事务隔离级别 mysql事务 数据库事务

电子书:《Linux Perf Master》

RiboseYim

Linux 性能优化

芋道 Spring Cloud Alibaba 介绍

艿艿

阿里巴巴 分布式 微服务 Spring Cloud Spring Boot

Linux 性能诊断:负载评估入门

RiboseYim

Linux 性能优化

【gRPC】Python调用Java的gRPC服务

遇见

Java Python gRPC

OKR实践中的痛点(1):老板的KR我的O,怎么办?

大叔杨

OKR Scrum 敏捷

一个创业者的途中思考

非著名程序员

创业 读书笔记 程序员 重新理解创业 思考

【数据结构】双向链表插入操作的时间复杂度分析

遇见

数据结构 算法 时间复杂度

业务代码必须要做的事情

程序员劝退师

初入响应式编程(上)

CD826

spring 微服务 Spring Cloud 响应式编程 reactor

Flink初体验

数据社

大数据 flink 流计算

人们喜欢彼此制造困难让大家难过

Fenng

寻找伴侣最重要的是什么?

二爷

用声音在一起,听荔枝CTO丁宁聊UGC声音互动平台的技术世界

ONES 王颖奇

内容 企业架构 互联网

分享多年积累的 macOS 效率工具

张晓辉

macos

浅谈汽车行业嵌入式软件发布的流程有多复杂

WB

程序员 软件

测试

Chonge

写一个开源的 macOS 程序可以赚多少钱?

子骅 luin

node.js redis GitHub 开源 赚钱

可视化Java垃圾回收_Java_Ben Evans_InfoQ精选文章