垃圾清理势在必行——java垃圾收集算法

合集下载

深入理解Java垃圾收集

深入理解Java垃圾收集

深入理解Java垃圾收集(GC)机制垃圾收集(Garbage Collection ,GC),是一个长久以来就被思考的问题,当考虑GC的时候,我们必须思考3件事情:哪些内存需要回收?什么时候回收?如何回收?那么在Java中,我们要怎么来考虑GC呢?首先回想以下内存区域的划分,其中程序计数器、本地方法栈、虚拟机栈三个区域随线程而生,随线程释放,栈中的栈帧随着方法的进入和退出执行着出栈和入栈的操作,每一个栈帧分配多少内存基本是在类结构确定时就已经固定的(可能会进行一些优化,但是大体上已知),因此这几个区域就不需要考虑回收的问题,因为方法结束或者线程结束时,内存自然都被回收。

不需要额外的GC算法等。

然而Java堆和方法区则不一样,一个接口所对应的多个实现类所需要的内存可能不一样,一个方法中的多个分支所需要的内存也可能不一样,我们只有在程序处于运行期间才能知道程序需要创建那些对象,这部分的内存的分配和回收是动态的,因此,垃圾收集器关注的是这方面的内存。

一、如何确定对象可以回收1、引用计数算法最容易想到与理解的算法,即对于每一个对象,每当该对象被引用时,计数器值就+1,引用失效时,计数器就-1。

因此,当对象的引用计数为0时,即为不可再被使用的。

该算法也在一些领域被使用来进行内存管理,但是JAVA虚拟机中并没有选用该算法。

主要是因为不能很好的解决循环引用的问题。

事实上会被判定为死亡对象,因为JAVA虚拟机不是采用引用计数来进行判断的,因此如果发生垃圾回收,c1,c2 都会被回收内存。

2、可达性分析Java、C#的主流实现都是采用该种方式,来判断对象是否存活。

这个算法的基本思路就是一系列“GC Roots”作为起始点,从这些节点向下搜索,搜索到的所有引用链中的对象都是可达的,其余的对象都是不可达的,如上例,即使c1,c2互相引用,但是c1,c2都不属于GC Roots对象,因此都不可达。

Java中,以下几种对象可以作为GC Roots:①虚拟机栈(栈帧中的本地变量表)中引用的对象。

JVM垃圾回收算法及分代垃圾收集器

JVM垃圾回收算法及分代垃圾收集器

JVM垃圾回收算法及分代垃圾收集器⼀、垃圾收集器的分类1、次收集器 Scavenge GC,指发⽣在新⽣代的GC,因为新⽣代的Java对象⼤多都是朝⽣⼣死,所以Scavenge GC⾮常频繁,⼀般回收速度也⽐较快。

当Eden空间不⾜以为对象分配内存时,会触发Scavenge GC。

⼀般情况下,当新对象⽣成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进⾏GC,清除⾮存活对象,并且把尚且存活的对象移动到Survivor区。

然后整理Survivor的两个区。

这种⽅式的GC是对年轻代的Eden区进⾏,不会影响到年⽼代。

因为⼤部分对象都是从Eden区开始的,同时Eden区不会分配的很⼤,所以Eden区的GC会频繁进⾏。

因⽽,⼀般在这⾥需要使⽤速度快、效率⾼的算法,使Eden去能尽快空闲出来。

当年轻代堆空间紧张时会被触发,相对于全收集⽽⾔,收集间隔较短。

2、全收集器 Full GC,指发⽣在⽼年代的GC,出现了Full GC⼀般会伴随着⾄少⼀次的Minor GC(⽼年代的对象⼤部分是Scavenge GC过程中从新⽣代进⼊⽼年代),⽐如:分配担保失败。

Full GC的速度⼀般会⽐Scavenge GC慢10倍以上。

当⽼年代内存不⾜或者显式调⽤System.gc()⽅法时,会触发Full GC。

当⽼年代或者持久代堆空间满了,会触发全收集操作。

可以使⽤System.gc()⽅法来显式的启动全收集,全收集⼀般根据堆⼤⼩的不同,需要的时间不尽相同,但⼀般会⽐较长。

3、垃圾回收器的常规匹配⼆、常见垃圾回收算法1、引⽤计数(Reference Counting) ⽐较古⽼的回收算法。

原理是此对象有⼀个引⽤,即增加⼀个计数,删除⼀个引⽤则减少⼀个计数。

垃圾回收时,只⽤收集计数为0的对象。

此算法最致命的是⽆法处理循环引⽤的问题。

2、复制(Copying) 此算法把内存空间划为两个相等的区域,每次只使⽤其中⼀个区域。

Java的垃圾回收机制:强制回收System.gc()Runtime.getTime().gc()

Java的垃圾回收机制:强制回收System.gc()Runtime.getTime().gc()

Java的垃圾回收机制:强制回收System.gc()Runtime.getTime().gc()垃圾回收当引⽤类型的实体,如对象、数组等不再被任何变量引⽤的时候。

这块占⽤的内存就成为了垃圾。

JVM会根据⾃⼰的策略决定是回收内存注意:1. 垃圾回收只回收内存中的对象,⽆法回收物理资源(数据库连接,⽹络IO等)2. 程序⽆法精确的控制台垃圾回收的运⾏,垃圾回收汇总任何时候进⾏,系统⾃动。

3. 在垃圾回收机制回收任何对象之前总会调⽤他的finalize()⽅法。

对象在内存中的三种状态:1. 可达状态:对象有变量再引⽤。

2. 可恢复状态:如果⼀个对象没有任何变量引⽤它,但是调⽤了finalize()后⼜有新的变量引⽤了对象,中间的状态为“可恢复状态”。

3. 不可达状态:对象没有变量引⽤,并且重新调⽤了finalize()⽅法后,还没有变成可达状态,就变为不可达状态,系统开始回收资源。

强制垃圾回收System.gc() Runtime.getRuntime.gc()package com.zmd.study.rubbish;import ;/*** @ClassName RubbishTest* @projectName: object1* @author: Zhangmingda* @description:测试⼲预垃圾回收* date: 2021/4/6.*/public class RubbishTest {private String name;//构造⽅法public RubbishTest(String name) { = name;}//重写finalize增加输出便于观察是否⾃动回收了对象@Overrideprotected void finalize() throws Throwable {System.out.println(name + "要被回收了");super.finalize();}//测试创建多个对象,看垃圾有没有⾃动回收public static void main(String[] args) {for(int i=0;i<1000; i++) {new RubbishTest("name" + i);System.out.println("循环打印" + "name" + i);//强制垃圾回收,当没有变量引⽤上⾯new出来的对象,就会调⽤finalize()⽅法回收内存System.gc();//Runtime.getRuntime().gc();} } }。

Java垃圾回收策略

Java垃圾回收策略

Java垃圾回收策略随着软件开发的不断发展,内存管理一直被认为是一个重要的议题。

在传统的编程语言中,程序员需要手动管理内存,这给开发者带来了很大的负担。

为了解决这个问题,Java引入了垃圾回收机制,使得程序员不需要关心内存的分配和释放,大大简化了程序的开发。

Java的垃圾回收机制是基于自动垃圾回收器(Garbage Collector, GC)实现的。

自动垃圾回收器会周期性地检查程序中的对象,标记出不再被使用的对象,并释放它们占用的内存空间。

这样,开发人员就不需要手动释放内存,大大降低了内存管理的复杂度。

在Java中,垃圾回收策略主要分为四种类型:标记-清除、复制、标记-整理和分代回收。

不同的策略适用于不同的场景,下面将逐一介绍这四种策略。

1. 标记-清除(Mark-Sweep)标记-清除是最基本的垃圾回收算法之一。

它通过标记不再使用的对象,并在标记完成后,清除这些对象所占用的内存空间。

标记-清除算法的缺点是会产生内存碎片,这可能会导致内存分配时出现不连续的空间,影响程序的性能。

2. 复制(Copying)复制算法是将内存分为两个相等的部分,每次只使用其中一部分。

当一部分的内存空间用完后,将还存活的对象复制到另一部分,然后清除已使用的那部分。

复制算法的优点是不会产生内存碎片,但是也会导致内存利用率降低。

3. 标记-整理(Mark-Compact)标记-整理算法在标记-清除算法的基础上做了改进。

它通过标记不再使用的对象,并将存活的对象向一端移动,然后清理整理出连续的内存空间。

标记-整理算法解决了标记-清除算法的内存碎片问题,但仍然可能导致内存利用率较低。

4. 分代回收(Generational)分代回收算法是基于一种观察:大部分对象在创建后很快就变得不可达。

基于这个观察,分代回收算法将内存分为多个代(Generation),并根据对象的年龄将其放置在不同的代中。

这样,在垃圾回收时,只需要对某一代的对象进行回收,提高了回收效率。

JAVA垃圾回收-可达性分析算法

JAVA垃圾回收-可达性分析算法

JAVA垃圾回收-可达性分析算法在java中是通过引⽤来和对象进⾏关联的,也就是说如果要操作对象,必须通过引⽤来进⾏。

那么很显然⼀个简单的办法就是通过引⽤计数来判断⼀个对象是否可以被回收。

不失⼀般性,如果⼀个对象没有任何引⽤与之关联,则说明该对象基本不太可能在其他地⽅被使⽤到,那么这个对象就成为可被回收的对象了。

这种⽅式成为引⽤计数法。

这种⽅式的特点是实现简单,⽽且效率较⾼,但是它⽆法解决循环引⽤的问题,因此在Java中并没有采⽤这种⽅式(Python采⽤的是引⽤计数法)。

看下⾯这段代码:public class Main {public static void main(String[] args) {MyObject object1 = new MyObject();MyObject object2 = new MyObject();object1.object = object2;object2.object = object1;object1 = null;object2 = null;}}class MyObject{public Object object = null;}最后⾯两句将object1和object2赋值为null,也就是说object1和object2指向的对象已经不可能再被访问,但是由于它们互相引⽤对⽅,导致它们的引⽤计数都不为0,那么垃圾收集器就永远不会回收它们。

为了解决这个问题,在Java中采取了可达性分析法。

该⽅法的基本思想是通过⼀系列的“GC Roots”对象作为起点进⾏搜索,如果在“GC Roots”和⼀个对象之间没有可达路径,则称该对象是不可达的,不过要注意的是被判定为不可达的对象不⼀定就会成为可回收对象。

被判定为不可达的对象要成为可回收对象必须⾄少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。

深入理解Java垃圾回收机制

深入理解Java垃圾回收机制

深入理解Java垃圾回收机制Java作为一门面向对象的编程语言,其垃圾回收机制是其核心功能之一。

Java垃圾回收机制以其高效、可靠的特性,为程序员们带来了很大的便利。

但对于初学者和一些开发者,Java垃圾回收机制还是比较神秘的。

本文将从深入理解Java垃圾回收机制方面进行探讨。

Java垃圾回收机制的概念对于Java垃圾回收机制,我们首先需要了解的是垃圾回收机制的概念。

简单来说,垃圾回收机制就是在程序运行时,自动清除不再使用的对象,并回收其占用的内存空间。

这样做既能够让程序节省内存空间,也可以避免内存泄漏等问题的发生。

Java垃圾回收机制的执行方式Java垃圾回收机制的执行方式可以分为两种,即标记-清除法和复制-清除法。

1. 标记-清除法标记-清除法是指,当垃圾回收机制开始工作时,它会标记所有正在使用的对象和被使用的对象之间的关系。

然后,它会扫描程序中所有的对象,并将被使用的对象打上“标记”,将不再使用的对象打上“不可达标记”。

最后,垃圾回收机制回收那些被打上“不可达标记”的对象,并释放其占用的内存空间。

2. 复制-清除法复制-清除法是指,当垃圾回收机制开始工作时,它会将整个可用内存区域分为两个相等的部分,分别称为“From”空间和“To”空间。

当程序对象在进行分配内存时,垃圾回收机制会将对象分配在From空间中。

当From空间被占满时,垃圾回收机制会暂停程序运行,并将所有存活的对象从From空间复制到To空间,然后将From空间进行清除,最后将To空间作为新的From空间。

这种方式既能够让内存得到有效的利用,也可以确保程序的稳定运行。

Java垃圾回收机制的内存分区Java垃圾回收机制的内存分区可以分为程序计数器、虚拟机栈、方法区、堆(Heap)四个部分。

其中,程序计数器保存下一个要执行的指令的地址;虚拟机栈保存线程方法的信息;方法区保存类、方法及常量池的信息;堆是程序运行时所使用的内存区域。

Java垃圾回收机制的垃圾收集器Java垃圾回收机制的垃圾收集器是Java虚拟机中专门负责回收垃圾对象的模块,其具体实现方式取决于Java虚拟机的版本和厂商。

Java的垃圾回收机制

Java的垃圾回收机制

Java的垃圾回收机制引言Java是一种面向对象的编程语言,具有强大的垃圾回收机制。

垃圾回收机制是Java虚拟机(JVM)的核心组成部分,它负责自动管理内存,释放不再使用的对象,减少内存泄漏和资源浪费。

本文将详细介绍Java的垃圾回收机制,包括垃圾回收算法、垃圾回收器以及一些优化技术。

一、垃圾回收算法垃圾回收算法是指在进行垃圾回收时,如何判断一个对象是否可以被回收。

Java 中常用的垃圾回收算法有以下几种:1. 引用计数算法引用计数算法是最简单的一种垃圾回收算法。

它通过在对象中维护一个引用计数器,每当有一个引用指向这个对象时,计数器加1;当一个引用不再指向这个对象时,计数器减1。

当引用计数器为0时,表示对象不再被引用,可以被垃圾回收。

然而,引用计数算法存在一个问题,即循环引用的对象无法被回收。

2. 标记-清除算法标记-清除算法是一种基于根对象的垃圾回收算法。

它首先从根对象开始,通过可达性分析标记所有可达对象,然后清除未标记的对象。

标记-清除算法能够回收循环引用的对象,但它存在碎片化问题,即回收后的内存空间不连续,容易导致内存分配的效率下降。

3. 复制算法复制算法是一种将内存划分为两个区域的垃圾回收算法。

它将存活的对象从一个区域复制到另一个区域,然后清除原来的区域。

复制算法解决了标记-清除算法的碎片化问题,但它的缺点是需要额外的内存空间。

4. 标记-整理算法标记-整理算法是一种综合了标记-清除算法和复制算法的垃圾回收算法。

它首先从根对象开始标记可达对象,然后将所有存活的对象移动到一端,清除剩余的对象,并且将地址连续的存活对象整理在一起。

标记-整理算法解决了标记-清除算法的碎片化问题,并且不需要额外的内存空间。

二、垃圾回收器垃圾回收器是实现垃圾回收算法的具体执行者。

Java虚拟机提供了多个垃圾回收器,可以根据应用程序的需求进行配置。

1. Serial收集器Serial收集器是一种单线程的垃圾回收器,它采用复制算法。

Java虚拟机内存模型及垃圾回收算法解析

Java虚拟机内存模型及垃圾回收算法解析

Java虚拟机内存模型及垃圾回收算法解析Java虚拟机是一种用于执行Java字节码的虚拟机器。

它有自己的内存模型和垃圾回收算法,用于有效地管理内存并自动处理不再使用的对象。

Java虚拟机内存模型可以分为线程私有的程序计数器、虚拟机栈和本地方法栈;线程共享的堆;以及方法区。

每个线程在执行时都包含一个程序计数器,用于指示执行的字节码指令。

虚拟机栈用于存储局部变量、方法参数和方法调用的状态信息。

而本地方法栈用于支持本地方法的调用和执行。

堆是Java虚拟机管理的最大的内存区域,用于存储对象实例。

它是内存分配和垃圾回收的主要区域。

在堆中分配的对象由垃圾回收器自动回收,以释放不再使用的内存。

方法区用于存储已加载的类信息、常量和静态变量。

垃圾回收是Java虚拟机的一项重要功能。

它通过自动检测和清除不再使用的对象来释放内存。

在Java中,垃圾回收是自动进行的,程序员无需手动管理内存。

Java虚拟机中的垃圾回收算法可以分为标记-清除算法、复制算法和标记-整理算法。

标记-清除算法首先标记所有活跃对象,然后清除所有未标记的对象。

这种算法的缺点是会导致内存碎片,影响内存的利用率。

复制算法将堆内存分为两个部分,每次只使用其中一个部分。

当发生垃圾回收时,将存活的对象复制到另一部分,并清除当前部分的所有对象。

这种算法的缺点是只能使用堆内存的一半空间。

标记-整理算法首先标记活跃对象,然后将它们移动到堆的一端,并清除剩余部分。

与标记-清除算法相比,标记-整理算法可以减少内存碎片。

除了以上提到的垃圾回收算法,Java虚拟机还有其他高级垃圾回收算法,如分代收集、并发标记清除和并发标记整理。

这些算法可以进一步提高垃圾回收的效率和性能。

总结而言,Java虚拟机的内存模型和垃圾回收算法是为了提供高效的内存管理和自动回收不再使用的对象。

开发人员只需专注于业务逻辑的编写,而无需手动管理内存。

通过了解和理解Java虚拟机的内存模型和垃圾回收算法,可以更好地编写高效的Java程序。

Java垃圾回收新算法

Java垃圾回收新算法

Java垃圾回收新算法
Java 从诞生以来以其在网络应用开发上独特的魅力以及一次开发,随处运行的可移植性引起了人们极大的兴趣。

Java 与以往的高级语言如C/C++相比,在开发方面具有很大的优势,其中以对象内存管理机制中的垃圾处理机制(GC) 最为突出。

1 C/C++与Java 对象内存管理差别
C/C++将内存划分成四部分:数据区、代码区、栈区、堆区。

Java 则把内存划分成三部分即代码区、栈区、堆区,代码区主要用于存放程序的代码,栈区主要用于存放局部变量、内部变量等中间性变量,堆区主要用来存放对象。

C/C++中的对象内存管理是通过语句new()/delete()或malloc()/free()进行申请和释放的。

用new()或malloc()申请内存后,若不使用delete()或free()进行释放,则所申请的内存一直被占用,即使不使用也不能自动释放,必须人为释放,导致编程工作很繁琐。

Java 中的对象内存管理则改进了对内存的释放过程,使用new()或其他方法申请的内存在不使用时,可以自动进行垃圾处理,释放内存,从而节省内存,使内存的使用更加高效、合理。

Java 中可以通过三种方法来销毁对象实现内存释放,这三种方法被称为Java 销毁对象的三把利剑:垃圾回收器;finalize 方法;利用System.gc 方法强制启动垃圾回收器。

垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,按照特定的垃圾收集算法实现资源自动回收的功能系统,会自动进行GC 策略。

Java垃圾回收机制总结

Java垃圾回收机制总结

Java垃圾回收机制总结java垃圾回收机制释放那些不再被任何活动对象引⽤的java对象从GC Root作为起点,进⾏链路访问,可以达到的是活跃对象,达不到的是不活跃对象,会被回收。

被GC Root引⽤的对象:虚拟机栈中引⽤的对象⽅法区中的类静态属性引⽤的对象⽅法区中常量引⽤的对象本地⽅法栈中JNI中引⽤的对象GC的算法:引⽤计数:引⽤了+1,没有引⽤-1,为0就被回收。

缺点:现在不⽤了;每次对象赋值需要维护引⽤计数器,计数器本⾝也是⼀种消耗;较难处理循环引⽤。

复制:Young区--Old区Young区:Eden,From,To第⼀步:当Eden区满时会触发第⼀次GC,把还活着的对象拷贝到Survivor from区,当Eden'区再次触发GC时,会扫描Eden区和From区,对这两个区域进⾏垃圾回收,还存活着的放到To区,同时把年龄加1。

如果到达⽼年的标准,放到Old区。

⼀般是15.第⼆步:清空eden和survivorFrom,复制之后有交换,谁空谁是To。

第三步:To和From互换。

⼀般交换15次还是存活,就放⼊⽼年代。

(MaxTenuringThreshold决定)。

优点是没有碎⽚。

缺点是空间⽤的多。

标记清除(mark-sweep)先标记出要回收的对象,然后统⼀回收这些对象。

优点:节约空间。

缺点:会有碎⽚。

标记整理压缩(mark-compact)先标记,再次进⾏扫描,并往⼀端滑动存活对象。

优点:没有碎⽚。

缺点:需要移动对象的成本。

耗时间四种主要的垃圾收集器:串⾏,并⾏,并发,GC。

它们的具体实现:1. Serial(串⾏):单线程环境下使⽤⼀个线程进⾏GC。

会Stop-the-world。

新⽣代⽤的复制,⽼年代⽤的标记压缩。

简单⾼效,对单个cpu环境并且没有线程交互的开销,性能⽐较好。

开启⽅式:-xx:+useSerialGC。

默认的⽼年代是SerialOld。

2. ParNew(并⾏):多个GC收集器并⾏⼯作。

Java的垃圾收集(Garbage Collection)

Java的垃圾收集(Garbage Collection)

Java的垃圾收集(Garbage Collection)我记得在我刚开始学习Java的时候,总是有很多学习Java的前辈们在反复地为我讲述Java 的优点,比如“Write Once, Run Anywhere”之类,但是我记得印象最深的还是垃圾收集器,因为可以不用自己操心内存的管理。

不过当时只知道这些脏活累活都让垃圾收集器这个家伙给干掉了,其他的就不知云里雾里。

而且当时还老是觉得把这么重要的事情交给这个家伙总有点不放心,毕竟没有自己亲自动手来得踏实。

不过,随着了解的深入,越来越感觉到这个家伙的可爱。

毕竟我们不用再亲自去过问烦人的内存管理,不用时刻提心吊胆是不是忘记了释放哪个对象,而且这个家伙确实把内存打理得井井有条。

既然这个家伙做着这么重要的事情,而且给我们带来了这么多的好处,我想我们还是有必要来了解一下它。

至少,要是有一天哪个不负责任的程序员把自己程序的错误都推到垃圾收集器的身上,你就可以义正言辞地揭穿他的谎言。

而且只有了解它,你才可能真正地掌握它,用好它甚至优化它。

什么是垃圾收集呢?垃圾收集(Garbage Collection,简称GC)其实是一种动态存储管理技术。

主要是按照特定的垃圾收集算法(Garbage Collection algorithm 简称GC算法)来实现自动资源回收的功能。

简单地说,就是将那些程序中释放内存的代码由系统在后台自动地完成,这样的一种机制就被称作垃圾收集,能提供这种功能的编程语言,我们就说它支持GC,比如典型的Java、C#、Python等,本文主要讨论HotSpot(详见说明一)系列Java虚拟机(JVM)中的GC。

为什么采用GC?我相信每个初次接触GC的人都会有此一问?想要弄清楚GC如此流行的原因,就必须首先了解它的作用,它到底能干些什么?显而易见它省去了程序员自己管理内存的麻烦和危险。

在没有GC的年代,我们必须及时地释放我们霸占的内存,但同时在释放之前又必须弄清楚这些内存是不是能够被释放。

Java中的垃圾回收机制是如何工作的

Java中的垃圾回收机制是如何工作的

Java中的垃圾回收机制是如何工作的在 Java 编程的世界里,垃圾回收机制是一项至关重要的特性,它就像是一位默默工作的“清洁工”,负责自动管理内存的分配和释放,让开发者能够更专注于业务逻辑的实现,而不必过度操心内存管理的繁琐细节。

要理解 Java 中的垃圾回收机制是如何工作的,首先得明白什么是垃圾。

在 Java 中,当一个对象不再被任何引用所指向,也就是没有任何途径能够访问到它时,这个对象就被视为垃圾。

想象一下,一个对象就像是一个房间,如果没有钥匙能打开这个房间的门,那么这个房间里的东西也就没有用了,它就变成了垃圾。

那么,Java 是如何发现这些垃圾对象的呢?这主要通过两种方式:引用计数法和可达性分析算法。

引用计数法的原理比较简单直观。

给每个对象添加一个引用计数器,每当有一个地方引用这个对象时,计数器就加 1;当引用失效时,计数器就减 1。

当计数器的值为 0 时,就表明这个对象没有被引用,可以被当作垃圾回收。

然而,这种方法存在一个问题,那就是无法解决循环引用的情况。

比如对象 A 引用了对象 B,对象 B 又引用了对象 A,但除此之外没有其他地方引用它们,按照引用计数法,它们的计数器都不为 0,但实际上它们已经不再被使用了,是应该被回收的垃圾。

相比之下,可达性分析算法就更强大和准确。

它从一些被称为“GC Roots”的对象出发,沿着引用链向下搜索。

如果一个对象不能从任何“GC Roots”对象通过引用链到达,那么这个对象就被认为是不可达的,是垃圾。

“GC Roots”对象通常包括虚拟机栈(栈帧中的本地变量表)中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象以及本地方法栈中 JNI(即 Java Native Interface)引用的对象。

当垃圾回收器确定了哪些对象是垃圾之后,就会开始进行回收操作。

Java 的垃圾回收算法主要有标记清除算法、复制算法、标记压缩算法以及分代收集算法。

简单介绍Java垃圾回收机制

简单介绍Java垃圾回收机制

简单介绍Java垃圾回收机制Java的内存分配与回收全部由JVM垃圾回收进程⾃动完成。

与C语⾔不同,Java开发者不需要⾃⼰编写代码实现垃圾回收。

这是Java深受⼤家欢迎的众多特性之⼀,能够帮助程序员更好地编写Java程序。

这篇教程是系列第⼀部分。

⾸先会解释基本的术语,⽐如JDK、JVM、JRE和HotSpotVM。

接着会介绍JVM结构和Java堆内存结构。

理解这些基础对于理解后⾯的垃圾回收知识很重要。

Java关键术语JavaAPI:⼀系列帮助开发者创建Java应⽤程序的封装好的库。

Java开发⼯具包(JDK):⼀系列⼯具帮助开发者创建Java应⽤程序。

JDK包含⼯具编译、运⾏、打包、分发和监视Java应⽤程序。

Java虚拟机(JVM):JVM是⼀个抽象的计算机结构。

Java程序根据JVM的特性编写。

JVM针对特定于操作系统并且可以将Java指令翻译成底层系统的指令并执⾏。

JVM确保了Java的平台⽆关性。

Java运⾏环境(JRE):JRE包含JVM实现和JavaAPI。

JavaHotSpot虚拟机每种JVM实现可能采⽤不同的⽅法实现垃圾回收机制。

在收购SUN之前,Oracle使⽤的是JRockitJVM,收购之后使⽤HotSpotJVM。

⽬前Oracle拥有两种JVM实现并且⼀段时间后两个JVM实现会合⼆为⼀。

HotSpotJVM是⽬前OracleSE平台标准核⼼组件的⼀部分。

在这篇垃圾回收教程中,我们将会了解基于HotSpot虚拟机的垃圾回收原则。

JVM体系结构下⾯图⽚总结了JVM的关键组件。

在JVM体系结构中,与垃圾回收相关的两个主要组件是堆内存和垃圾回收器。

堆内存是内存数据区,⽤来保存运⾏时的对象实例。

垃圾回收器也会在这⾥操作。

现在我们知道这些组件是如何在框架中⼯作的。

Java堆内存我们有必要了解堆内存在JVM内存模型的⾓⾊。

在运⾏时,Java的实例被存放在堆内存区域。

当⼀个对象不再被引⽤时,满⾜条件就会从堆内存移除。

Jvm垃圾回收机制

Jvm垃圾回收机制

Jvm垃圾回收机制Jvm垃圾回收机制(根据java编程思想进⾏总结)⾸先打个⽐⽅C++⾥⾯的堆想象成⼀个院⼦,⾥⾯每个对象都负责管理⾃⼰的地盘,⼀段时间以后,对象可能被销毁,但地盘必须加以重⽤。

但在某些java虚拟机中堆的分配更像是传送带,没分配⼀个对象,他就往前移动⼀格。

但是java的堆并不是完全像传送带那样⼯作,那样会导致频繁的内存页⾯调度进⽽影响到性能。

其中的关键在与垃圾回收器的介⼊,当堆在⼯作的时候,将⼀⾯回收空间,⼀⾯使堆中对象紧凑的排列,这样“堆指针”就更容易移动到靠近传送带的开始处,也就尽量避免了页⾯的错误。

通过垃圾回收器对对象重新排列,实现了⼀种⾼速的,有⽆限空间的可供分配的堆模型。

⾸先了解下其他的垃圾回收机制:⼀、引⽤计数引⽤计数是⼀种简单但是很慢的垃圾回收技术。

每个对象都含有⼀个引⽤计数器,当有引⽤链接⾄对象时,引⽤计数加1。

当引⽤离开作⽤于或被设置为null时,引⽤计数减1.虽然管理引⽤技术的开销不⼤,但这项开销在整个程序的⽣命周期中将持续发⽣。

垃圾回收期会在含有全部对象的列表上遍历,当发现某个对象的引⽤计数为0时,就释放其占⽤的空间(但是引⽤计数模式经常会在记数值变为0时⽴即释放对象)。

这个⽅法存在⼀种缺陷,如果对象之间存在循环引⽤,可能会出现“对象应该被回收,但引⽤记数却不为0”的情况。

引⽤记数常⽤来说明垃圾收集的⼯作⽅式,单似乎未被⽤⽤于任何⼀种java虚拟机实现中。

⼆、停⽌-复制(stop-and-copy)将所有存活的对象复制到新堆,其他都是垃圾缺陷:1.两个堆2.稳定状态下,还是会发⽣复制。

解决办法:1.堆中分配⼏块较⼤的内存,复制发⽣在较⼤的内存块。

2.标记—清扫B.基于“对于任何活的对象,⼀定能最终追溯到其存活在堆栈或静态存储区之中的引⽤。

”java虚拟机将采⽤⼀种⾃适应的垃圾回收技术。

⾄于如何找到存活对象,取决于不同的java虚拟机实现。

⼀种做法名叫停⽌-复制(stop-and-copy),意味着先暂停程序的运⾏(所以它不属于后台回收模式),然后将所有存活的对象从当前堆复制到另⼀个堆,没有被复制的全部都是垃圾。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

垃圾清理势在必行——java垃圾收集算法
阅读次数: 299次发布时间: 2010-02-23 15:23:14发布人: 大Q
来源: 天极网
1.垃圾收集算法的核心思想
Java语言建立了垃圾收集机制,用以跟踪正在使用的对象和发现并回收不再使用(引用)的对象。

该机制可以有效防范动态内存分配中可能发生的两个危险:因内存垃圾过多而引发的内存耗尽,以及不恰当的内存释放所造成的内存非法引用。

垃圾收集算法的核心思想是:对虚拟机可用内存空间,即堆空间中的对象进行识别,如果对象正在被引用,那么称其为存活对象,反之,如果对象不再被引用,则为垃圾对象,可以回收其占据的空间,用于再分配。

垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能,因此需要开发人员做比较深入的了解。

2.触发主GC(Garbage Collector)的条件
JVM进行次GC的频率很高,但因为这种GC占用时间极短,所以对系统产生的影响不大。

更值得关注的是主GC的触发条件,因为它对系统影响很明显。

总的来说,有两个条件会触发主GC:
①当应用程序空闲时,即没有应用线程在运行时,GC会被调用。

因为GC在优先级最低的线程中进行,所以当应用忙时,GC线程就不会被调用,但以下条件除外。

②Java堆内存不足时,GC会被调用。

当应用线程在运行,并在运行过程中创建新对象,若这时内存空间不足,JVM就会强制地调用GC线程,以便回收内存用于新的分配。

若GC一次之后仍不能满足内存分配的要求,JVM会再进行两次GC作进一步的尝试,若仍无法满足要求,则 JVM将报“out of memory”的错误,Java 应用将停止。

由于是否进行主GC由JVM根据系统环境决定,而系统环境在不断的变化当中,所以主GC的运行具有不确定性,无法预计它何时必然出现,但可以确定的是对一个长期运行的应用来说,其主GC是反复进行的。

3.减少GC开销的措施
根据上述GC的机制,程序的运行会直接影响系统环境的变化,从而影响GC的触发。

若不针对GC的特点进行设计和编码,就会出现内存驻留等一系列负面影响。

为了避免这些影响,基本的原则就是尽可能地减少垃圾和减少GC过程中的开销。

具体措施包括以下几个方面:
(1)不要显式调用System.gc()
此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。

(2)尽量减少临时对象的使用
临时对象在跳出函数调用后,会成为垃圾,少用临时变量就相当于减少了垃圾的产生,从而延长了出现
上述第二个触发条件出现的时间,减少了主GC的机会。

(3)对象不用时最好显式置为Null
一般而言,为Null的对象都会被作为垃圾处理,所以将不用的对象显式地设为Null,有利于GC收集器判定垃圾,从而提高了GC的效率。

(4)尽量使用StringBuffer,而不用String来累加字符串(详见blog另一篇文章JAVA中String与StringBuffer)
由于String是固定长的字符串对象,累加String对象时,并非在一个String对象中扩增,而是重新创建新的String对象,如Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作“+”操作时都必须创建新的String对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。

避免这种情况可以改用StringBuffer来累加字符串,因StringBuffer是可变长的,它在原有基础上进行扩增,不会产生中间对象。

(5)能用基本类型如Int,Long,就不用Integer,Long对象
基本类型变量占用的内存资源比相应对象占用的少得多,如果没有必要,最好使用基本变量。

(6)尽量少用静态对象变量
静态变量属于全局变量,不会被GC回收,它们会一直占用内存。

(7)分散对象创建或删除的时间
集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增加主GC的频率。

集中删除对象,道理也是一样的。

它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC的机会。

相关文档
最新文档