Java垃圾回收机制 入门
对于Java虚拟机的了解,我认为是一个Java程序员已经入门的重要标志,而JVM中的垃圾回收机制(Garbage Collection,简称GC)又是JVM中的重点,所以hans在这里用篇文章时间和大家一起了解一下GC。
GC是Java平台中最重要的标志之一,它最早诞生于有MIT研发的一门叫做Lisp的语言之中,所以它的历史要比Java更悠久。在它广泛使用之前,程序员要经常处理由于内存处理不完善而引起的bug。但是即使在内存处理极其完善的今天,我们这些想成为优秀程序员的程序猿,也不能将它视为透明,因为当垃圾收集成为系统达到更高并发量的瓶颈的时候,我们必须会对它实施必要的监控和调节。
其实在垃圾回收机制刚刚诞生的时候,关于内存,人们就经常想3个问题:
- 哪些内存需要回收?
- 什么时候回收?
- 怎么回收?
这几个问题咱们一个个看。
先说哪些内存需要回收
众所周知,Java的内存大体可划分为方法区、栈(虚拟机栈和本地方法栈)、堆。因为栈是线程私有的,每一个栈中的内存如何分配,基本上在编译期就已知了,同时这部分内存随着线程或方法的结束就跟着回收了,所以栈中的内存分配和回收具有确定性。但堆和方法区就不一样了,由于具有“动态绑定”和“运行时产生新常量”等特性,所以这部分的内存是在运行期分配的,是不确定的,内存回收指的就是回收这一部分的内存。
知道了要回收的内存是堆中和方法区中的内存,现在需要知道就是“什么时候回收”了。(抢答————在调用System.gc()的时候回收。抢答正确!但如果就这么简单我会在这里另起一段?)
这里说的是“什么时候回收”确切的说是“内存处于什么状态时回收”(骂我表述不准确?我愿意,你来打我呀!)一般来讲大家的第一个反应是“有地方引用它就不回收、没地方引用就回收”,很好!这是一个很棒的思路(Python的垃圾回收就是用的这种思路)但是你细想想这种思路有一个比较致命的问题,想到是什么了吗?没想到就看看下面的代码吧。
public class Test {
public Test instace = null;
public static void main(String[] args) {
Test testA = new Test();
Test testB = new Test();
testA.instace = testB;
testB.instace = testA;
testA = null;
testB = null;
}
}
这种思路的致命问题就是它存在对象间循环引用的问题,像上面例子中的testA和testB已经无法访问了,理应被回收。但是由于它们互相引用着对方,所以它们有地方被引用,利用上述思路就无法回收。如何解决这种问题呢?
“可达性分析”就可以完美解决这种问题,可达性分析是通过一些“根”作为起点,将“根”能引用到的对象加入“可达对象集合”中,再讲其中的对象引用到的对象加入该集合中,重复这个过程直到没有任何对象可以加入该集合。我们得到的这个集合就是不用回收的对象集合,剩下的就都可以回收了。现在问题来了,“根”是什么呢?(我不会告诉你它是火之国木叶村的地下忍者组织。活跃一下气氛别太当真)“根”也是对象,包括下面几种:
- 栈中所引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
就如上面那个例子,testA和testB虽然都被别人引用,但是无法从“根”开始达到它们,所以“可达性分析”就很成功的解决了循环引用的问题,所以现在Java、C#等都用的是这种方式来确定哪些对象可以回收。
现在前两个问题解决了,开始解决第三个问题——怎么回收?
最简单的方法就是将可以回收的对象标记一下,然后召唤“对象回收程序”将它们回收,这种方法即简单又可行,但存在一个关键的问题(就知道不可能这么简单)那就是——碎片化。想象一下,内存是连续的,但可回收对象的位置是随机的,这样就导致了内存回收后,虽然有很大的内存空间,但是这些内存空间被一些“不可被回收的对象”分成了一个个小块,若重新整理一遍内存、清理碎片又要花费大量的时间。为了解决这个问题出现了两种优秀的解决办法分别是“复制法”和“标记-整理法”
先谈谈“标记-整理法”。这种方式其实将内存回收和内存碎片整理合二为一的方法,让两个工作同时进行,从而极大的减少了时间。它是在可以回收的对象标记之后,将不可回收的对象向内存一端移动,这个过程中直接可以将部分可回收的对象覆盖,当移动完成后,直接清空边界以外的内存。这样就极大的减少了回收后再进行碎片整理的时间。
再来看看“复制法”。这种方式的原形是将内存分为两块,分配对象时只在其中的“内存块1”上操作,当这一块用完了之后,将不可以被回收的对象复制到“内存块2”上去,然后将“内存块1”清空。这种方式会比上面那种方法还要快,但是存在一个不足,就是让分配对象时的内存缩小为原来的一半,这显然不是很合算。人们通过观察发现,新建立的对象会有很大一部分是可回收的,所以就有了一种更巧妙的改进版。
这种改进版就是将内存分成一块较大的Eden空间和两块较小的Survivor空间(以HotSpot为例,大小比例是8:1:1),每次使用Eden和一个Survivor。回收时,将两者中存活的对象复制到另一Survivor中,然后清空这两个内存空间。这样的话之会有10%的内存被浪费。通过这样的改进“复制法”的性能就是很可观的了。但是也有时会有大量的对象存活下来,导致Survivor空间不够用,这就使人们加深对对象存活的观察和思考。
观察发现虽然刚刚新建的对象“可被回收率”高达98%,但经过几轮回收后剩下来的对象,一般是经常要用到的,很少可以被回收。所以人们就想可以将Survivor空间中存活了几轮的对象,放到一个新的空间中,在这个空间每次回收的对象会相对较少,因此可以将回收频率调低。这一部分的回收方法自然要用到“标记-整理法”,并且将这部分称为“老年代”,将刚刚新建的对象称为“新生代”。“新生代”的内存回收用“复制法”而老年代用“标记-整理法”,这样的方式就是现在大部分虚拟机采用的“分代收集法”
关于GC的基本理论就讲到这里了,以后等我再有所长进,再跟大家深入的讨论。这篇文章可能有一些错误或不足,希望大家及时通知我会改的。
Java垃圾回收机制 入门的更多相关文章
- 【转载】Java垃圾回收机制
原文地址:http://www.importnew.com/19085.html Java垃圾回收机制 说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联 ...
- 【转】深入理解 Java 垃圾回收机制
深入理解 Java 垃圾回收机制 一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再 ...
- 深入理解java垃圾回收机制
深入理解java垃圾回收机制---- 一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再 ...
- Java垃圾回收机制_(转载)
Java垃圾回收机制 说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联系起来.在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给 ...
- 成为Java GC专家(3)—如何优化Java垃圾回收机制
为什么需要优化GC 或者说的更确切一些,对于基于Java的服务,是否有必要优化GC?应该说,对于所有的基于Java的服务,并不总是需要进行GC优化,但前提是所运行的基于Java的系统,包含了如下参数或 ...
- java 垃圾回收机制 引用类型
Java语言的一个重要特性是引入了自动的内存管理机制,使得开发人员不用自己来管理应用中的内存.C/C++开发人员需要通过malloc/free 和new/delete等函数来显式的分配和释放内存.这对 ...
- 【Java】Java垃圾回收机制
Java垃圾回收机制 说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联系起来.在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给 ...
- Java垃圾回收机制的工作原理
Java垃圾回收机制的工作原理 [博主]高瑞林 [博客地址]http://www.cnblogs.com/grl214 获取更多内容,请关注小编个人微信公众平台: 一.Java中引入垃圾回收机制的作用 ...
- Java 垃圾回收机制(早期版本)
Java 垃圾回收机制在我们普通理解来看,应该视为一种低优先级的后台进程来实现的,其实早期版本的Java虚拟机并非以这种方式实现的. 先从一种很简单的垃圾回收方式开始. 引用计数 引用计数是一种简单但 ...
随机推荐
- Summernote
Summernote是一个基于jquery的bootstrap超级简单WYSIWYG在线编辑器.Summernote非常的轻量级,大小只有30KB,支持Safari,Chrome,Firefox.Op ...
- 第一周:Java基础知识总结(1)
1.软件开发的基本步骤: 1.分析问题,建立数据模型. 2.确定数据结构类型和算法. 3.编写程序. 4.调试程序. 2.Java语言 Java是一种简单的.面向对象的.分布式的.解释的.安全的.可移 ...
- HttpContextBase转换成HttpContext对象
有以下方法: 主要是方式就是通过context获取HttpApplication,然后通过Application获取相应的HttpContext ①HttpContext context=HttpCo ...
- Maven(二)使用eclipse创建maven多模块项目
maven作为一种自动化构建工具,在现在的企业应用开发中运用非常普遍. 企业项目一般都比较大,多采用maven管理的多模块项目,下面直接上创建步骤 一.创建一个maven项目
- AX7: Install a deployable package
Table of Contents Introduction Key concepts Collect topology configuration data Generate a runbook f ...
- 如何定位Sharepoint网站集所在的w3wp进程
方法1. 直接开始运行,输入cmd,再输入iisapp可以列出当前所有IIS中的WebApplication所对应的w3wp.exe进程,后面都有一个进程号标识,在VS中调试的时候附加到对应进 ...
- MongoDB学习笔记(入门)
一.文档的注意事项:1. 键值对是有序的,如:{ "name" : "stephen", "genda" : "male&quo ...
- 在win7下将CapsLock按键变成esc
我喜欢用vim来编辑,经常要按到esc,但是去按那个按键确实比较的远,而且CapsLock这个按键对我来说着实有些鸡肋,所以就想在win7上也能像ubuntu那样把capslock映射为esc,在网上 ...
- Debian7下初次尝试Nginx+Uwsgi部署Django开发环境
之前一直都用的是新浪的SAE,但是由于各种限制,各种不爽,终于下定决心开始折腾VPS,于是在搬瓦工上买了个年付VPS,开始折腾之旅. 由于对Linux一窍不通,所以不知道如何在Linux上部署开发环境 ...
- jquery中的ajax参数
jquery中将ajax封装成了函数,我们使用起来非常方便,jquery会自动根据内容选择post还是get方式提交数据,并且会自动编码,但是要想完全掌握jquery中的ajax,我们必须将它的各个参 ...